202509_NBWS_logbool

Tags:流量分析,正则匹配,布尔盲注,pyshark,DASCTF

0x00. 题目

找到flag,格式为DASCTF{}

附件路径:https://pan.baidu.com/s/1GyH7kitkMYywGC9YJeQLJA?pwd=Zmxh#list/path=/CTF附件

附件名称:202509_NBWS_logbool.zip

0x01. WP

1. 分析流量结构

初筛http协议,发现大量SQL注入请求,初步判断为SQL注入流量复现

图片

从返回包内容来看,请求包对目标字符串的每个字符的ASCII值通过SQL语句进行逻辑判断,若逻辑成立则会返回success关键词,反之则只显示语句

SELECT * FROM ctfuser WHERE id='1' AND ORD(MID((SELECT IFNULL(CAST(content AS NCHAR),0x20) FROM ctftest.ctfblob ORDER BY id LIMIT 0,1),60,1))>50 AND 'aOIj'='aOIj' LIMIT 0,1</br></br>success

图片

重新浏览注入请求,发现只针对三个字段,分别是username,passwordcontent,那么只要解析其中一个也就能用同样脚本解析其他两个

2. 编写exp.py提取数据

使用过滤表达式(http.request.full_uri contains "username") && (tcp.srcport == 80)先对username的返回包进行筛选,并套用之前编写的通用脚本框架,提取请求数据request.full_uri和响应内容data-text-lines

import pyshark
import re
import urllib.parse

strTsharkPath = "D:\\=Green=\\Wireshark\\App\\Wireshark\\"
strCapPath = "logbool.pcapng"
# 分别筛选出username,password和content
strFomula='(http.request.full_uri contains  "username") && (tcp.srcport == 80)'

cap= pyshark.FileCapture(strCapPath, display_filter=strFomula,tshark_path=strTsharkPath)

# 协议结构分析开始
print("协议结构分析开始...")
i=0
for layer in cap[1].layers:
    print("第",i+1,"层:",layer.layer_name)
    print(layer.field_names)
    i+=1
print("协议结构分析完成。")
print("=" * 16)
sResult=[]

for pkt in cap:
    intRequestNumber = pkt.number
    print("\r\tFrame Number: %s" % str(intRequestNumber), end="")
    
    for layer in pkt.layers:
        if layer.layer_name == "http":  # 指定协议层
            sURI=layer.get_field_value("request.full_uri")  #指定字段
            sURI=urllib.parse.unquote(sURI)
            print("request.full_uri: ",sURI)
                
        if layer.layer_name =="data-text-lines":
            print("data-text-lines: ",str(layer))

运行结果如下:

D:\=CTF缓存=\20250919_市信息中心竞赛\logbool>python exp.py
协议结构分析开始...
第 1 层: null
['family']
第 2 层: ip
['version', 'hdr_len', 'dsfield', 'dsfield_dscp', 'dsfield_ecn', 'len', 'id', 'flags', 'flags_rb', 'flags_df', 'flags_mf', 'frag_offset', 'ttl', 'proto', 'checksum', 'checksum_status', 'src', 'addr', 'src_host', 'host', 'dst', 'dst_host', 'stream']
第 3 层: tcp
['srcport', 'dstport', 'port', 'stream', 'stream_pnum', 'completeness', 'completeness_rst', 'completeness_fin', 'completeness_data', 'completeness_ack', 'completeness_syn_ack', 'completeness_syn', 'completeness_str', 'len', 'seq', 'seq_raw', 'nxtseq', 'ack', 'ack_raw', 'hdr_len', 'flags', 'flags_res', 'flags_ae', 'flags_cwr', 'flags_ece', 'flags_urg', 'flags_ack', 'flags_push', 'flags_reset', 'flags_syn', 'flags_fin', 'flags_str', 'window_size_value', 'window_size', 'window_size_scalefactor', 'checksum', 'checksum_status', 'urgent_pointer', '', 'time_relative', 'time_delta', 'analysis', 'analysis_initial_rtt', 'analysis_bytes_in_flight', 'analysis_push_bytes_sent', 'payload']
第 4 层: http
['', 'response_version', 'response_code', 'response_code_desc', 'response_phrase', 'server', 'response_line', 'date', 'content_type', 'transfer_encoding', 'connection', 'content_encoding', 'response', 'request_in', 'time', 'request_uri', 'request_full_uri', 'chunk_size', 'chunk_data', 'chunk_boundary', 'file_data']
第 5 层: data-text-lines
['']
协议结构分析完成。
================
        Frame Number: 108471
request.full_uri:  http://10.211.55.8/?id=1' AND ORD(MID((SELECT IFNULL(CAST(username AS NCHAR),0x20) FROM ctftest.ctfblob ORDER BY id LIMIT 0,1),1,1))>64 AND 'hiCz'='hiCz
data-text-lines:  Layer DATA-TEXT-LINES
:       SELECT * FROM ctfuser WHERE id='1' AND ORD(MID((SELECT IFNULL(CAST(username AS NCHAR),0x20) FROM ctftest.ctfblob ORDER BY id LIMIT 0,1),1,1))>64 AND 'hiCz'='hiCz' LIMIT 0,1</br></br>success

        Frame Number: 108512
request.full_uri:  http://10.211.55.8/?id=1' AND ORD(MID((SELECT IFNULL(CAST(username AS NCHAR),0x20) FROM ctftest.ctfblob ORDER BY id LIMIT 0,1),1,1))>96 AND 'hiCz'='hiCz
data-text-lines:  Layer DATA-TEXT-LINES
:       SELECT * FROM ctfuser WHERE id='1' AND ORD(MID((SELECT IFNULL(CAST(username AS NCHAR),0x20) FROM ctftest.ctfblob ORDER BY id LIMIT 0,1),1,1))>96 AND 'hiCz'='hiCz' LIMIT 0,1</br></br>success

        Frame Number: 108553
request.full_uri:  http://10.211.55.8/?id=1' AND ORD(MID((SELECT IFNULL(CAST(username AS NCHAR),0x20) FROM ctftest.ctfblob ORDER BY id LIMIT 0,1),1,1))>112 AND 'hiCz'='hiCz
data-text-lines:  Layer DATA-TEXT-LINES
:       SELECT * FROM ctfuser WHERE id='1' AND ORD(MID((SELECT IFNULL(CAST(username AS NCHAR),0x20) FROM ctftest.ctfblob ORDER BY id LIMIT 0,1),1,1))>112 AND 'hiCz'='hiCz' LIMIT 0,1</br></br>

... ...

3. 增加正则匹配,根据返回包特征调整注入字符的ASCII值

提取SQL注入操作的字符索引和对应的ASCII值,当返回包中包含success内容时表示判断成立,即实际的ASCII=ASCII+1

调整exp.py

import pyshark
import re
import urllib.parse

strTsharkPath = "D:\\=Green=\\Wireshark\\App\\Wireshark\\"
strCapPath = "logbool.pcapng"
# 分别筛选出username,password和content
strFomula='(http.request.full_uri contains  "username") && (tcp.srcport == 80)'


cap= pyshark.FileCapture(strCapPath, display_filter=strFomula,tshark_path=strTsharkPath)

# 协议结构分析开始
print("协议结构分析开始...")
i=0
for layer in cap[1].layers:
    print("第",i+1,"层:",layer.layer_name)
    print(layer.field_names)
    i+=1
print("协议结构分析完成。")
print("=" * 16)
sResult=[]

for pkt in cap:
    intRequestNumber = pkt.number
    print("\r\tFrame Number: %s" % str(intRequestNumber))
    
    for layer in pkt.layers:
        if layer.layer_name == "http":  # 指定协议层
            sURI=layer.get_field_value("request.full_uri")  #指定字段
            sURI=urllib.parse.unquote(sURI)
            print(sURI)
            
            # SELECT * FROM ctfuser WHERE id='1' AND ORD(MID((SELECT IFNULL(CAST(content AS NCHAR),0x20) FROM ctftest.ctfblob ORDER BY id LIMIT 0,1),60,1))>50 AND 'aOIj'='aOIj' LIMIT 0,1</br></br>success         
            sT=re.findall(rf'(.*?)LIMIT 0,1\),(.*?),1\)\)>(.*?) AND(.*?)',sURI)

            intIndex=int(sT[0][1])
            intASCII=int(sT[0][2])
            if len(sResult)<intIndex:
                sResult.append('')
                
        if layer.layer_name =="data-text-lines":
            print(str(layer))
            if "success" in str(layer):
                intASCII=intASCII+1
            sResult[intIndex-1]=chr(intASCII)
            

print("".join(sResult))
print("\r")

# boolblob

同理,修改过滤表达式为(http.request.full_uri contains "password") && (tcp.srcport == 80)'得到password内容为timeemitloggol

4. 修正脚本,获取content

修改过滤表达式为(http.request.full_uri contains "content") && (tcp.srcport == 80)'获取content内容时发现脚本报错

... ...
        Frame Number: 41340
http://10.211.55.8/?id=1' AND ORD(MID((SELECT IFNULL(CAST(content AS NCHAR),0x20) FROM ctftest.ctfblob ORDER BY id LIMIT 0,1),130,1))!=53 AND 'aOIj'='aOIj
Traceback (most recent call last):
  File "D:\=CTF缓存=\20250919_市信息中心竞赛\logbool\exp.py", line 37, in <module>
    intIndex=int(sT[0][1])
                 ~~^^^
IndexError: list index out of range

D:\=CTF缓存=\20250919_市信息中心竞赛\logbool>

分析报错请求对应的语句判断逻辑为!=而不是>,查看对应的请求和返回数据,仅仅是对某个字符爆破的过程请求,不影响最终结果,增加容错判断

... ...
            sT=re.findall(rf'(.*?)LIMIT 0,1\),(.*?),1\)\)>(.*?) AND(.*?)',sURI)
			# 若未匹配到有效数据,忽略本次请求和响应
            if len(sT)<1:
                continue
            intIndex=int(sT[0][1])
            intASCII=int(sT[0][2])
... ...

最终得到content内容为
526172211a0701003392b5e50a01050600050101808000b2b1f3d65502033cb00004a80020a09ebf0280030008666c61672e747874300100030fedd6cdb8cc2535d8819161a4c7f5b2b05912735d7a3fd51074b03e4d9a68c5ec47766f7c7e9491369e1d8add0a0302eefeaba7a446d80100cf48e5373135a4b7de8993121c592e8c87743c2e8c0fffb766b53217f07acac40b55cf1db67923bea02a55299c54991d77565103050400

5.HEX导入文件,顺利获得flag

content内容导入十六进制编辑器发现头部特征为Rar!,另存为rar文件。

使用前期解析出来的password解压后得到flag为DASCTF{33c12355cd508de6b9b3676b97ece17e}

图片

图片

0x02. 总结

由于平时代码写得不多,前后耗费近半小时,作为一个2个小时时长的线下赛,整体来说本次赛题还是做得酣畅淋漓,继续沉淀...

posted @ 2025-09-20 19:17  JasonJHu  阅读(66)  评论(0)    收藏  举报