跳转至

SHELLCTF2022 tea

1 IDA64

int __cdecl main(int argc, const char **argv, const char **envp)
{
  boilWater();
  if ( strlen(pwd) == 32 )
  {
    addSugar();
    addTea();
    addMilk();
    strainAndServe();
  }
  else
  {
    puts("wrong length");
  }
  return 0;
}
__int64 boilWater()
{
  printf("Enter the flag: ");
  return __isoc99_scanf("%s", pwd);
}
unsigned __int64 addSugar()
{
  int i; // [rsp+4h] [rbp-5Ch]
  char v2[8]; // [rsp+10h] [rbp-50h] BYREF
  __int64 v3; // [rsp+18h] [rbp-48h]
  char v4; // [rsp+20h] [rbp-40h]
  char dest[8]; // [rsp+30h] [rbp-30h] BYREF
  __int64 v6; // [rsp+38h] [rbp-28h]
  char v7; // [rsp+40h] [rbp-20h]
  unsigned __int64 v8; // [rsp+48h] [rbp-18h]

  v8 = __readfsqword(0x28u);
  *(_QWORD *)v2 = 0LL;
  v3 = 0LL;
  v4 = 0;
  *(_QWORD *)dest = 0LL;
  v6 = 0LL;
  v7 = 0;
  for ( i = 0; i < strlen(pwd); ++i )
  {
    if ( (i & 1) != 0 )
      strncat(v2, &pwd[i], 1uLL);
    else
      strncat(dest, &pwd[i], 1uLL);
  }
  strncat(v2, dest, 0x11uLL);
  strcpy(pwd, v2);
  return __readfsqword(0x28u) ^ v8;
}
unsigned __int64 addTea()
{
  size_t v0; // rbx
  size_t v1; // rbx
  char src; // [rsp+7h] [rbp-49h] BYREF
  int i; // [rsp+8h] [rbp-48h]
  int j; // [rsp+Ch] [rbp-44h]
  char dest[8]; // [rsp+10h] [rbp-40h] BYREF
  __int64 v7; // [rsp+18h] [rbp-38h]
  __int64 v8; // [rsp+20h] [rbp-30h]
  __int64 v9; // [rsp+28h] [rbp-28h]
  char v10; // [rsp+30h] [rbp-20h]
  unsigned __int64 v11; // [rsp+38h] [rbp-18h]

  v11 = __readfsqword(0x28u);
  *(_QWORD *)dest = 0LL;
  v7 = 0LL;
  v8 = 0LL;
  v9 = 0LL;
  v10 = 0;
  for ( i = 0; ; ++i )
  {
    v0 = i;
    if ( v0 >= strlen(pwd) >> 1 )
      break;
    src = pwd[i] + 3 * (i / -2);
    strncat(dest, &src, 1uLL);
  }
  for ( j = strlen(pwd) >> 1; ; ++j )
  {
    v1 = j;
    if ( v1 >= strlen(pwd) )
      break;
    src = pwd[j] + j / 6;
    strncat(dest, &src, 1uLL);
  }
  strcpy(pwd, dest);
  return __readfsqword(0x28u) ^ v11;
}
unsigned __int64 addMilk()
{
  size_t v0; // rax
  size_t v1; // rax
  int v3; // [rsp+4h] [rbp-ACh]
  char dest[8]; // [rsp+10h] [rbp-A0h] BYREF
  __int64 v5; // [rsp+18h] [rbp-98h]
  __int64 v6; // [rsp+20h] [rbp-90h]
  __int64 v7; // [rsp+28h] [rbp-88h]
  char v8; // [rsp+30h] [rbp-80h]
  char s[8]; // [rsp+40h] [rbp-70h] BYREF
  __int64 v10; // [rsp+48h] [rbp-68h]
  __int64 v11; // [rsp+50h] [rbp-60h]
  __int64 v12; // [rsp+58h] [rbp-58h]
  char v13; // [rsp+60h] [rbp-50h]
  char v14[8]; // [rsp+70h] [rbp-40h] BYREF
  __int64 v15; // [rsp+78h] [rbp-38h]
  __int64 v16; // [rsp+80h] [rbp-30h]
  __int64 v17; // [rsp+88h] [rbp-28h]
  char v18; // [rsp+90h] [rbp-20h]
  unsigned __int64 v19; // [rsp+98h] [rbp-18h]

  v19 = __readfsqword(0x28u);
  v3 = 0;
  *(_QWORD *)dest = 0LL;
  v5 = 0LL;
  v6 = 0LL;
  v7 = 0LL;
  v8 = 0;
  *(_QWORD *)s = 0LL;
  v10 = 0LL;
  v11 = 0LL;
  v12 = 0LL;
  v13 = 0;
  *(_QWORD *)v14 = 0LL;
  v15 = 0LL;
  v16 = 0LL;
  v17 = 0LL;
  v18 = 0;
  while ( pwd[v3] != '5' && v3 < strlen(pwd) )
    strncat(dest, &pwd[v3++], 1uLL);
  while ( pwd[v3] != 'R' && v3 < strlen(pwd) )
    strncat(s, &pwd[v3++], 1uLL);
  while ( v3 < strlen(pwd) )
    strncat(v14, &pwd[v3++], 1uLL);
  v0 = strlen(dest);
  strncat(v14, dest, v0);
  v1 = strlen(s);
  strncat(v14, s, v1);
  strcpy(pwd, v14);
  return __readfsqword(0x28u) ^ v19;
}
int strainAndServe()
{
  if ( !strcmp("R;crc75ihl`cNYe`]m%50gYhugow~34i", pwd) )
    return puts("yep, that's right");
  else
    return puts("nope, that's not it");
}

2 gdb调试

gdb调试,输入32位单词abcdefghijklmnopqrstuvwxyz012345,有如下输出:

# addSugar : $rdi   : 0x0000555555558040  →  "bdfhjlnprtvxz135acegikmoqsuwy024"
# addTea : 0x555555558040 <pwd>:    "bdcedfegfhgih\037\036 cehjlnpruwy{}479"
# addMilk  0x555555558040 <pwd>:    "bdcedfegfhgih\037\036 cehjlnpruwy{}479"
gdb调试,输入32位单词shellctf{abcdefghijklmnopqrstuv},有如下输出:
# addSugar 0x555555558040 <pwd>:    "hlcfacegikmoqsu}selt{bdfhjlnprtv"
# addTea : 0x555555558040 <pwd>:    "hl`c[]\\^]_^`_a`hugow~egilnprtvy{"
# addMilk  0x555555558040 <pwd>:    "hl`c[]\\^]_^`_a`hugow~egilnprtvy{"

r = b'abcdefghijklmnopqrstuvwxyz012345'

left=[]
right=[]
for i in range(len(r)):
   if (i&1 != 0):
       right.append(r[i])
   else:
       left.append(r[i])

cx =  bytes(right) + bytes(left)  
half = len(cx) // 2

r=[]
for i in range(0,half):
   r.append(cx[i]-3*(i//2))

for i in range(half,len(cx)):
   r.append(cx[i]+i//6)

bytes(r)  # b'bacbdcedfegfh\x1c\x1e\x1dehjlnpruwy{}479'

3 逆向

cx = b'R;crc75ihl`cNYe`]m%50gYhugow~34i'
#cx = b'hl`c[]\\^]_^`_a`hugow~egilnprtvy{'
half = len(cx) // 2

r=[]
for i in range(0,half):
   r.append(cx[i]+3*(i//2))

for i in range(half,len(cx)):
   r.append(cx[i]-i//6)


left=r[:half]
right=r[half:len(cx)]

flag = []
for i in range(half):
    flag.append(right[i])
    flag.append(left[i])

print(bytes(flag))

4 addMilk

从逆向代码看:addMilk函数对pwd进行拼接: - 开始到字符5存入dest - 当前位置到字符R存入s - 其它字符存入v14 - v14拼接dest和s拷贝到pwd

gdb设置pwd包含5和R:

set {char [32]} 0x0000555555558040 = "012345ABCDERabcdefghjkloiuytrewq"
gef➤  ni
gef➤  x/s 0x0000555555558040
0x555555558040 <pwd>:   "Rabcdefghjkloiuytrewq012345ABCDE"

set {char [32]} 0x0000555555558040 = "01234567ABCDEabcdeRfghjkloiuytrewq"
gef➤  ni
gef➤  x/s 0x0000555555558040
0x555555558040 <pwd>:   "Rfghjkloiuytrewq01234567ABCDEabcde"

可以看到,addMilk对pwd在R处切断,调换前后顺序后拼接,所有有32种爆破可能:

逆向addMilk

cx = b'R;crc75ihl`cNYe`]m%50gYhugow~34i'
for i in range(1,30):
    ct = cx[i:32] + cx[0:i]
    print(ct)

5 exp:

ct = b'R;crc75ihl`cNYe`]m%50gYhugow~34i'
half = 16
for i in range(1,30):
    cx = ct[i:32] + ct[0:i]
    r=[]
    for i in range(0,half):
       r.append(cx[i]+3*(i//2))

    for i in range(half,len(cx)):
       r.append(cx[i]-i//6)


    left=r[:half]
    right=r[half:len(cx)]

    flag = []
    for i in range(half):
        flag.append(right[i])
        flag.append(left[i])

    print(bytes(flag))

shellctf{T0_1nfiNi7y_4nD_B3y0nd}