首页
社区
课程
招聘
[原创]MTCTF-PSA-Writeup
发表于: 2021-7-5 02:33 13044

[原创]MTCTF-PSA-Writeup

2021-7-5 02:33
13044

PSA这道题当时归到PWN类型下,到比赛截止是2sol。但其实这道题主要问题还是在它的逆向部分。有点后悔当时没有早点看这道题,比赛结束后半个小时把这题解出来了,美团CTF差一道题没进决赛,不然将来美团实习转正的时候说不定还能吹吹这个经历

IDA打开看到给了一个很像是登录的逻辑判断 :
图片描述如果用户名和密码对了就给你进到栈溢出函数vuln():

进入到先前的函数,可以看到题目进行了很多大数库操作,包括执行了bn_mod_exp之类的函数,基本上就可以判定是RSA,下面的代码我略修改过,所以基本上容易看清

那么接下的核心问题是确定公钥N和e:
图片描述
注意到这里的e是用十六进制去存储的,也就是{0x01, 0x00, 0x01},即65537。N是小端序存储的,即0xdbea...
回到核心判断逻辑:

以用户名为例,读入用户名后经过public_block_operation的一轮RSA加密,结果存放在v11中,然后v11首先去除掉首部的空字节,然后以Qword形式存放到s中,说穿了就是截取加密后密文的前8个字节,然后去和'root'作比较,这里可以用GDB简单调试验证下:
我输入的username是'aaa\n',跟进来在strcmp之前rsi的值与RSA加密结果的前几位一致
图片描述
图片描述
下面那个password处理和这个同理,只不过加了一个简单异或,就不再赘述。
那么问题的核心就在于找到一个明文字符串,用公钥加密后的前几个字节必须是root。那么直接用\x00填充构建一个8字节的密文'root\x00\x00\x00\x00',然后反推明文,这个就是解RSA或模方程的问题了,不难,此题公钥N可以容易地被分解,password部分是同理的。

最后是栈溢出部分,题目还给了一个backdoor,里面是system('/bin/sh'),只要覆盖返回地址为backdoor地址就行了,但是我记得这题开了随机地址+覆盖字节数限制,只有一定的概率能覆盖成功。exp如下即可进入栈溢出函数:

栈溢出以后getshell,当时的老图贴上来
图片描述

int vuln()
{
  __int64 buf; // [rsp+0h] [rbp-10h]
  __int64 v2; // [rsp+8h] [rbp-8h]
 
  buf = 0LL;
  v2 = 0LL;
  printf("You can set message: ", 0LL, 0LL);
  read(0, &buf, 0x1AuLL);
  return printf("OK, recv!", &buf);
}
int vuln()
{
  __int64 buf; // [rsp+0h] [rbp-10h]
  __int64 v2; // [rsp+8h] [rbp-8h]
 
  buf = 0LL;
  v2 = 0LL;
  printf("You can set message: ", 0LL, 0LL);
  read(0, &buf, 0x1AuLL);
  return printf("OK, recv!", &buf);
}
signed __int64 __fastcall public_block_operation(__int64 a1, unsigned int *a2, __int64 a3, unsigned int a4, _DWORD *a5)
{
  _DWORD *v6; // [rsp+8h] [rbp-468h]
  char v7; // [rsp+30h] [rbp-440h]
  char m; // [rsp+140h] [rbp-330h]
  char e; // [rsp+250h] [rbp-220h]
  char c; // [rsp+360h] [rbp-110h]
  unsigned int edigits; // [rsp+468h] [rbp-8h]
  unsigned int ndigits; // [rsp+46Ch] [rbp-4h]
 
  v6 = a5;
  bn_decode((__int64)&m, 65u, a3, a4);
  bn_decode((__int64)&v7, 0x41u, (__int64)(v6 + 1), 256);
  bn_decode((__int64)&e, 0x41u, (__int64)(v6 + 65), 256);
  ndigits = bn_digits((__int64)&v7, 65);
  edigits = bn_digits((__int64)&e, 65);
  if ( (signed int)bn_cmp((__int64)&m, (__int64)&v7, ndigits) >= 0 )
    return 4097LL;
  bn_mod_exp((__int64)&c, (__int64)&m, (__int64)&e, edigits, (__int64)&v7, ndigits);
  *a2 = (unsigned int)(*v6 + 7) >> 3;
  bn_encode(a1, *a2, (__int64)&c, ndigits);
  memset(&c, 0, 0x104uLL);
  memset(&m, 0, 0x104uLL);
  return 0LL;
}
signed __int64 __fastcall public_block_operation(__int64 a1, unsigned int *a2, __int64 a3, unsigned int a4, _DWORD *a5)
{
  _DWORD *v6; // [rsp+8h] [rbp-468h]
  char v7; // [rsp+30h] [rbp-440h]
  char m; // [rsp+140h] [rbp-330h]
  char e; // [rsp+250h] [rbp-220h]
  char c; // [rsp+360h] [rbp-110h]
  unsigned int edigits; // [rsp+468h] [rbp-8h]
  unsigned int ndigits; // [rsp+46Ch] [rbp-4h]
 
  v6 = a5;
  bn_decode((__int64)&m, 65u, a3, a4);
  bn_decode((__int64)&v7, 0x41u, (__int64)(v6 + 1), 256);
  bn_decode((__int64)&e, 0x41u, (__int64)(v6 + 65), 256);
  ndigits = bn_digits((__int64)&v7, 65);
  edigits = bn_digits((__int64)&e, 65);
  if ( (signed int)bn_cmp((__int64)&m, (__int64)&v7, ndigits) >= 0 )
    return 4097LL;
  bn_mod_exp((__int64)&c, (__int64)&m, (__int64)&e, edigits, (__int64)&v7, ndigits);
  *a2 = (unsigned int)(*v6 + 7) >> 3;
  bn_encode(a1, *a2, (__int64)&c, ndigits);
  memset(&c, 0, 0x104uLL);
  memset(&m, 0, 0x104uLL);
  return 0LL;
}
puts("Login\nPlease input your name:");
  v13 = read(0, buf, 0x100uLL);
  public_block_operation((__int64)v11, (unsigned int *)&v10, (__int64)buf, v13, &pk);
  for ( i = 0; i <= 255 && !v11[i]; ++i )
    ;
  v0 = &v11[i];
  v1 = v0[1];
  *(_QWORD *)s2 = *v0;
  v9 = v1;
  puts("Please input your password:");
  memset(buf, 0, 0x100uLL);
  v13 = read(0, buf, 0x100uLL);
  public_block_operation((__int64)v11, (unsigned int *)&v10, (__int64)buf, v13, &pk);
  for ( i = 0; i <= 255 && !v11[i]; ++i )
    ;
  v2 = &v11[i];
  v3 = v2[1];
  *(_QWORD *)s = *v2;
  v7 = v3;
  if ( strcmp("root", s2) )
    goto LABEL_22;
  if ( strlen(s) != 6 )
    goto LABEL_22;
  i = 0;
  while ( i <= 5 )
  {
    v4 = i++;
    asc_2040A3[v4] ^= 0x11u;
  }
  if ( !strcmp(asc_2040A3, s) )
  {
    puts("Welcome back, administrator. ");
    result = vuln();
  }
puts("Login\nPlease input your name:");
  v13 = read(0, buf, 0x100uLL);
  public_block_operation((__int64)v11, (unsigned int *)&v10, (__int64)buf, v13, &pk);

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2021-7-5 02:40 被vagr4nt编辑 ,原因:
收藏
免费 3
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//