n1cef1sh's Blog

前言

上周和小伙伴打了个TJCTF,美国高中生的比赛也没那么吃得消=-=有一些题目的脑洞过大,工具新奇,也算是学到一些东西。就记录几个题目的解题过程。

题目

Interference(15points/270solvers)

简单隐写题目,给了两个看起来一样的图片。

首先还是尝试了盲水印,但是没有得到显著的结果。 于是用stegsolve把两张图合起来,偏移即可得到二维码,扫码得到flag。

flag:tjctf{m1x1ing_and_m4tchIng_1m4g3s_15_fun}

Math Whiz(20points/443solvers)

写的有点晚,端口给关了。就是一个简单的缓冲区溢出,借用一下别人的wp

python -c "print ('A'*100+'\n')*10" | nc problem1.tjctf.org 8001
******************** Please Register Below ********************
Full Name: Username: Password: Recovery Pin: Email: Address: Biography: Successfully registered 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' as an administrator account!
Here is your flag: tjctf{d4n63r0u5_buff3r_0v3rfl0w5}
timeout: the monitored command dumped core

Nothing but Everything(20points/110solvers)

My computer got infected with ransomware and now none of my documents are accessible anymore! If you help me out, I'll reward you a flag! 描述怪唬人的,还被勒索病毒给安排了。实际上解压以后得到一堆文件和文件夹,文件名和内容全都是数字。而且没有私钥公钥对,因此加密系统很简单,很可能是确定性的,很容易逆转。

猜测是按字节加密的,首先想到是16进制转换(但是当时处理的时候出错了= =),主文件夹的解密结果证实了确实是这样加密的,就想办法把所有的文件都解开。

毕竟文件数也不少,一个一个解还是麻烦。在别人的脚本里学习了os模块更快捷的处理文件目录。

来源

#!/usr/bin/env python
   
import os

directory = '1466921579'

def clarify(number):
	return hex(int(number))[2:].strip('L').decode('hex')

os.chdir(directory)
for i in os.listdir('.'):
	try:
		print clarify(i)
		c = open(i).read()
		open(clarify(i),'w').write(clarify(c))
	except:
		print "FAILED WITH",i

没想到解出各式各样的文件,但是问题是所有的文件都是已损坏无法打开。 不过放到linux下就能打开= =

最后在here(2).xlsx里找到flag

Grid Parser(45points/145solvers)

网格解析器?

不知道题目什么意思,解压压缩包,翻了一遍找到一个password.png

然后binwalk分析,发现zip,提取出来。

压缩包里有个flag.txt,但是压缩包需要密码。直接暴力破解即可。这里学到一个linux下的工具fcrackzip

USAGE: fcrackzip
  [-b|--brute-force]use brute force algorithm
  [-D|--dictionary] use a dictionary
  [-B|--benchmark]  execute a small benchmark
  [-c|--charset characterset]   use characters from charset
  [-h|--help]   show this message
  [--version]   show the version of this program
  [-V|--validate]   sanity-check the algortihm
  [-v|--verbose]be more verbose
  [-p|--init-password string]   use string as initial password/file
  [-l|--length min-max] check password with length min to max
  [-u|--use-unzip]  use unzip to weed out wrong passwords
  [-m|--method num] use method number "num" (see below)
  [-2|--modulo r/m] only calculcate 1/m of the password
  file...the zipfiles to crack

methods compiled in (* = default):

 0: cpmask
 1: zip1
*2: zip2, USE_MULT_TAB

密码也就是px,解压得到txt,里面就是flag:tjctf{n0t_5u5_4t_4LL_r1gHt?}

Huuuuuge(25points/64solvers)

当时没有做出来的题目,环境也关了,放一下参考wp。学习git。 https://ctftime.org/writeup/10731

Validator(30points/313solvers)

IDA打开通过字符串找到主程序即可看到一个flag格式的字符串。 但是提交错误,当然没有这么直接。但是也挺简单。找到替换字符的地方

tjctf{ju57_c4ll_m3_r3v3r53_60d_fr0m_n0w_0n} 变成

tjctf{ju57_c4ll_m3_35r3v3r_60d_fr0m_n0w_0n}

Python Reversing (40points/221solvers)

这个题目和另个所谓的“py-re”题目其实都算是密码题吧……

先看一下源码

import numpy as np

flag = 'redacted'

np.random.seed(12345)
arr = np.array([ord(c) for c in flag])
other = np.random.randint(1,5,(len(flag)))
arr = np.multiply(arr,other)

b = [x for x in arr]
lmao = [ord(x) for x in ''.join(['ligma_sugma_sugondese_'*5])]
c = [b[i]^lmao[i] for i,j in enumerate(b)]
print(''.join(bin(x)[2:].zfill(8) for x in c))

# original_output was 1001100001011110110100001100001010000011110101001100100011101111110100011111010101010000000110000011101101110000101111101010111011100101000011011010110010100001100010001010101001100001110110100110011101

逐位爆破即可,因为知道开头肯定是tjctf{,所以就按位爆破,每次添加8位二进制(如果没结果,就加9位,因为有的数转成2进制要大于FFFFFFFF)

import numpy as np
import string 
#flag = 'redacted'
str1 = string.printable

for s in str1:
	flag = 't'+ s
	np.random.seed(12345)
	arr = np.array([ord(c) for c in flag])
	other = np.random.randint(1,5,(len(flag)))
	arr = np.multiply(arr,other)
	b = [x for x in arr]
	lmao = [ord(x) for x in ''.join(['ligma_sugma_sugondese_'*5])]
	c = [b[i]^lmao[i] for i,j in enumerate(b)]
	t = ''.join(bin(x)[2:].zfill(8) for x in c)
	print t
	if t == '1001100001011110110100001100001010000011110101001100100011101111110100011111010101010000000110000011101101110000101111101010111011100101000011011010110010100001100010001010101001100001110110100110011101':
		print flag
		break

一直到最后爆破出结果。

bad cipher(50points/82solvers)

把另个python的题目一块看一下。源码如下

message = "[REDACTED]"
key = ""

r,o,u,x,h=range,ord,chr,"".join,hex

def e(m,k):
	l=len(k);s=[m[i::l]for i in r(l)]
	for i in r(l):
		a,e=0,""
		for c in s[i]:
			a=o(c)^o(k[i])^(a>>2)
			e+=u(a)
			s[i]=e
			return x(h((1<<8)+o(f))[3:]for f in x(x(y)for y in zip(*s)))

print(e(message,key))

flag = '473c23192d4737025b3b2d34175f66421631250711461a7905342a3e365d08190215152f1f1e3d5c550c12521f55217e500a3714787b6554'

首先去掉混淆

message = ""
key = ""


def encrypt(message,key):
	L=len(key)
	s=[message[i::L] for i in range(L)]
	for i in range(L):
		act=0
		enc=""
		for c in s[i]:
			act=ord(c)^ord(key[i])^(act>>2)
			enc+=chr(act)
			s[i]=enc
	return ''.join( hex(ord(y))[2:] for y in ''.join(''.join(x) for x in zip(*s)))

print encrypt(message,key)

最初这个题目让我很困扰,我以为key是需要求出来的flag,而message就是它给的”[REDACTED]”,但是s=[message[i::L] for i in range(L)这个分组说明key应该是比message短的,不然这个分组也没有什么意义。

但其实message才是要求的flag,key是比较短的那一个。关注加密部分的话其实不复杂,有几个地方注意一下。

那么在知道加密后结果的情况下,可以倒推出zip(*s)。也就是把那串flag每两位补0x 变成十六进制即可。

flag = '473c23192d4737025b3b2d34175f66421631250711461a7905342a3e365d08190215152f1f1e3d5c550c12521f55217e500a3714787b6554'
for i in range(0, len(flag), 2):
	aa = '0x'+ flag[i:i+2]
	print aa

112位flag也可以就此得知message应该是56位。

我们再来看key的长度应该是多少。当时出题人第一次放题的时候不小心透露了message和key,当时的key是8位。虽然之后立马改了题,但应该还是有参考价值的。因为key的长度肯定是56的因数,1, 2, 4, 7, 8, 14, 28 or 56,考虑到实际操作性,最可能的也就是4,7,8,14。

flag的格式我们知道,前六位当然是tjctf{,最后一位是}。根据加密的操作

for c in s[i]:
	act=ord(c)^ord(key[i])^(act>>2)
	enc+=chr(act)
	s[i]=enc

每组的第一次循环时,act=0,act»2=0,0异或一个数字还是等于那个数字本身。那么act=ord(c)^ord(key[i]),之后的每个字节加密都依赖于前一个字节。首先第一步我们可以求出key的第一位。

如果key是4位的话,第5个字节求出来应该是f。但是不成立,说明key大于4位。

然后我就尝试了8位,毕竟之前的key就是8位嘛(滑稽)。 按照8位key的话,经过一开始的分组分成8组,每组7个字节。把刚刚求出来的zip(*s)按照这个分组可以得到异或处理后的数据。

[[71, 91, 22, 5, 2, 85, 80], [60, 59, 49, 52, 21, 12, 10], [35, 45, 37, 42, 21, 18, 55], [25, 52, 7, 62, 47, 82, 20], [45, 23, 17, 54, 31, 31, 120], [71, 351, 70, 93, 30, 85, 123], [55, 102, 26, 8, 61, 33, 101], [2, 66, 121, 25, 92, 126, 84]]

这样八组的话我们已经知道了其中前六组第一个字节分别是tjctf{,最后一个一组的最后一个字节是},这样可以求出key的7位。*表示未知的第七位。

3V@mK<*6

这样就可以按位求出这七组的字符,至于第七组的话先用*填充,出来整体效果可以再推测数据。

tjctf{*4ybe  //很明显猜出这个地方的*是m 也就是maybe

由此推出第七位key‘[’,最后解出答案

tjctf{m4ybe_Wr1t3ing_mY_3ncRypT10N_MY5elf_W4Snt_v_sm4R7}

当时解出答案还挺开心,虽然一开始没有领悟到v 表示的是very的意思,但是觉得意思很通顺啊,或许我自己写出我的解密结果是不明智的233333,提交答案的时候第一次我把MY5elf里的M写成了m,改正后再提交显示这个答案已经提交过了???怎么改都不对,于是我操着蹩脚的英语询问了管理员

嗯,然后在最后面加了个;分号就正确了= =,大概是设置的大小写不区分识别?还有个槽点就是这里面的拼写错误……writeing,加ing不去e可还行???当然了参考了第一次的泄露出来flag里面也有 sh0ulndt这样低级的拼写错误,我就很有自信这个答案是正确的了= =

Lexington State Bank(40points/182solvers)

这是个让人蒙圈的lsb隐写题目。常规的LSB脚本试了试都不行。尝试各种分析因为不了解图片里面的东西所以没有得出结果。

赛后学到了一个很好用的png&bmp分析工具zsteg

We Will Rock You (75points/74solvers)

这是个做出来的人数比分数还低的题目=-=

虽然我没做出来,但是借着这个题目了解了一波狗币,仅次于比特币的虚拟货币。而且下了个题目里说的狗币钱包捣鼓了一波,但是不知道密码确实提取不到东西呀,更不要说私钥了,要是搞到私钥,那你的币就是我了(滑稽)。这个题也是积累到一个工具btcrecover,一个开源的比特币钱包密码和种子恢复工具,专为已经知道大部分密码/种子的情况而设计。

还了解到一个常用的字典rockyou.txt,这也是根据题目提示来的。

tjctf{tinkerbell}

Bricked Binary (80 points/107 solves)

我们有一个ELF二进制文件,它有一个参数,它用于称为哈希的加密函数。所以目标是找到flag。程序必须返回 22c15d5f23238a8fff8d299f8e5a1c62作为输出。

u和v这两个数组都可以直接提取出来。

v="81000000CD0000000A00000073000000B30000003B00000032000000B60000006E0000007C0000003100000057000000D1000000C5000000150000003A00000092000000B4000000E200000051000000AE000000420000005500000041000000E100000070000000300000001A0000000200000084000000A2000000E7000000B90000004D0000003C000000A30000000B000000B20000002B000000AB000000460000007E000000240000009C000000850000006F000000E4000000C40000005F000000CE0000004F0000000100000082000000FD0000006C000000AC000000DF000000640000000C000000A1000000E30000009E0000005D000000BB000000FE000000D30000002900000096000000C7000000F3000000FC00000065000000AA0000008A0000005A000000F5000000B700000038000000A50000008D000000D80000008E0000003900000007000000DE000000D50000001100000080000000E50000008900000035000000FF000000DD000000A60000001F000000230000000D000000C000000093000000C8000000670000001700000068000000180000008B00000062000000CC0000009D000000DA0000005600000066000000C60000007F000000E600000086000000E000000022000000C20000000F0000001B000000F60000002D0000006300000033000000910000007100000059000000EB000000A9000000D200000083000000BF0000003D0000006A00000008000000F9000000A70000004000000000000000E800000052000000BE000000FA0000004E0000002600000076000000CF000000540000007D0000001900000006000000F8000000D00000007400000028000000050000003F000000A00000001E000000C10000004500000049000000D4000000AF000000030000009B0000002F000000EE000000270000009A000000A400000097000000480000004A000000D90000003700000047000000AD00000044000000CA000000EF000000D7000000B8000000DB000000F00000009F0000005800000053000000EA0000002A0000007A00000036000000870000008C000000B50000007200000088000000B100000009000000F1000000160000003E0000006900000014000000EC00000025000000BC000000ED000000BA000000BD0000002C000000C9000000DC00000013000000F4000000750000001D0000004B000000C300000034000000100000006B00000077000000980000005E0000005C000000990000008F0000001200000094000000CB0000002E0000004C000000E900000020000000F70000004300000060000000FB0000006D0000001C000000780000000E000000B0000000D600000050000000790000007B0000006100000095000000A8000000040000005B000000F20000009000000021000000"
u="040000000700000005000000080000000C0000000A00000006000000020000000D00000001000000000000000E000000090000000B000000030000000F000000CA000000DE000000140000009400000029000000E9000000440000004B00000084000000E4000000D70000003A000000620000003F000000EF000000B70000007A0000009F000000F7000000FD0000005600000052000000B9000000C70000003E0000005C000000C4000000D5000000E1000000C900000093000000760000004800000088000000BF00000067000000A4000000EA000000D000000017000000CE00000098000000BB000000AC0000001C000000AB000000C100000026000000A600000083000000DD00000010000000960000009D00000080000000190000009C000000AF00000091000000D8000000AD000000A5000000B400000071000000DA000000F90000008C00000077000000A800000075000000A7000000550000003B000000FE000000E8000000ED0000006100000024000000950000005400000063000000AE0000004A000000DF0000003100000036000000F30000008D0000001D00000059000000470000005D00000074000000C00000006C0000002200000069000000BE000000EE0000008A00000034000000D30000001500000070000000BC000000F000000097000000F4000000E6000000D40000004C000000F100000079000000B800000073000000DC00000035000000D2000000CB0000005F0000008E000000C80000003800000032000000FB000000FA0000007B000000CD0000005A00000090000000A1000000A3000000580000008B000000B0000000D9000000B30000007D000000EB000000D100000078000000FC0000008600000050000000BD00000039000000C20000005E000000BA00000030000000230000004300000028000000CF0000006E000000E500000051000000DB000000B5000000A9000000E700000020000000210000006A000000B2000000F600000042000000E3000000E00000004F00000027000000810000002B0000007E000000A2000000F500000089000000D6000000FF0000001200000046000000400000009A000000600000007F0000002D000000130000001F00000087000000CC0000001A00000092000000110000002C000000B10000005700000085000000C6000000B600000066000000820000006B000000C30000001B000000160000006F00000037000000E2000000530000001E0000006D0000004E00000045000000640000002F00000072000000C5000000650000007C000000250000004100000049000000F80000003C0000002E000000AA000000330000008F0000004D000000680000009E0000005B0000003D000000EC00000099000000A00000009B00000018000000F20000002A00"

逆算法

ans="22c15d5f23238a8fff8d299f8e5a1c62"
flag=""
v="81000000CD0000000A00000073000000B30000003B00000032000000B60000006E0000007C0000003100000057000000D1000000C5000000150000003A00000092000000B4000000E200000051000000AE000000420000005500000041000000E100000070000000300000001A0000000200000084000000A2000000E7000000B90000004D0000003C000000A30000000B000000B20000002B000000AB000000460000007E000000240000009C000000850000006F000000E4000000C40000005F000000CE0000004F0000000100000082000000FD0000006C000000AC000000DF000000640000000C000000A1000000E30000009E0000005D000000BB000000FE000000D30000002900000096000000C7000000F3000000FC00000065000000AA0000008A0000005A000000F5000000B700000038000000A50000008D000000D80000008E0000003900000007000000DE000000D50000001100000080000000E50000008900000035000000FF000000DD000000A60000001F000000230000000D000000C000000093000000C8000000670000001700000068000000180000008B00000062000000CC0000009D000000DA0000005600000066000000C60000007F000000E600000086000000E000000022000000C20000000F0000001B000000F60000002D0000006300000033000000910000007100000059000000EB000000A9000000D200000083000000BF0000003D0000006A00000008000000F9000000A70000004000000000000000E800000052000000BE000000FA0000004E0000002600000076000000CF000000540000007D0000001900000006000000F8000000D00000007400000028000000050000003F000000A00000001E000000C10000004500000049000000D4000000AF000000030000009B0000002F000000EE000000270000009A000000A400000097000000480000004A000000D90000003700000047000000AD00000044000000CA000000EF000000D7000000B8000000DB000000F00000009F0000005800000053000000EA0000002A0000007A00000036000000870000008C000000B50000007200000088000000B100000009000000F1000000160000003E0000006900000014000000EC00000025000000BC000000ED000000BA000000BD0000002C000000C9000000DC00000013000000F4000000750000001D0000004B000000C300000034000000100000006B00000077000000980000005E0000005C000000990000008F0000001200000094000000CB0000002E0000004C000000E900000020000000F70000004300000060000000FB0000006D0000001C000000780000000E000000B0000000D600000050000000790000007B0000006100000095000000A8000000040000005B000000F20000009000000021000000"
u="040000000700000005000000080000000C0000000A00000006000000020000000D00000001000000000000000E000000090000000B000000030000000F000000CA000000DE000000140000009400000029000000E9000000440000004B00000084000000E4000000D70000003A000000620000003F000000EF000000B70000007A0000009F000000F7000000FD0000005600000052000000B9000000C70000003E0000005C000000C4000000D5000000E1000000C900000093000000760000004800000088000000BF00000067000000A4000000EA000000D000000017000000CE00000098000000BB000000AC0000001C000000AB000000C100000026000000A600000083000000DD00000010000000960000009D00000080000000190000009C000000AF00000091000000D8000000AD000000A5000000B400000071000000DA000000F90000008C00000077000000A800000075000000A7000000550000003B000000FE000000E8000000ED0000006100000024000000950000005400000063000000AE0000004A000000DF0000003100000036000000F30000008D0000001D00000059000000470000005D00000074000000C00000006C0000002200000069000000BE000000EE0000008A00000034000000D30000001500000070000000BC000000F000000097000000F4000000E6000000D40000004C000000F100000079000000B800000073000000DC00000035000000D2000000CB0000005F0000008E000000C80000003800000032000000FB000000FA0000007B000000CD0000005A00000090000000A1000000A3000000580000008B000000B0000000D9000000B30000007D000000EB000000D100000078000000FC0000008600000050000000BD00000039000000C20000005E000000BA00000030000000230000004300000028000000CF0000006E000000E500000051000000DB000000B5000000A9000000E700000020000000210000006A000000B2000000F600000042000000E3000000E00000004F00000027000000810000002B0000007E000000A2000000F500000089000000D6000000FF0000001200000046000000400000009A000000600000007F0000002D000000130000001F00000087000000CC0000001A00000092000000110000002C000000B10000005700000085000000C6000000B600000066000000820000006B000000C30000001B000000160000006F00000037000000E2000000530000001E0000006D0000004E00000045000000640000002F00000072000000C5000000650000007C000000250000004100000049000000F80000003C0000002E000000AA000000330000008F0000004D000000680000009E0000005B0000003D000000EC00000099000000A00000009B00000018000000F20000002A00"
for i in range(len(ans)/2):
key1=int(ans[32-(i+1)*2:32-(i+1)*2+2],16)
#print key1
key2=int(u[i*8:i*8+2],16)
#print key2
key3=key1^key2
key4=hex(key3)[2:]
if len(key4)==1:
key4="0"+key4
key4=key4.upper()
key5=v.find(key4)/8
if key5<30:
key5=v.rfind(key5)/8
flag+=chr(key5)
print flag[::-1]

得出flag

yummy_h45h_br0wn