Midterm 3-4
Midterm 3-4
Midterm 3-4
ShellShock
Prior to the vulnerability being fixed, the variable will not exist in the
child process, but there will be a function by the variable name, and
the function body will be the value of the variable.
Post the vulnerability being fixed, the child shell will have the same
variable as the parent.
Here's why:
As can be seen, the rm -rf in the variable definition got executed automatically when a
child was created.
The normal user account seed doesn't have access to delete /, but you could replace
the rm -rf / with rm -rf * which will remove all the contents of the home directory.
4. Instead of putting an extra shell command after a function definition,
we put it at the beginning (see the following example). We then run
Bash, which is vulnerable to the Shellshock attack. Will the shell
command echo world be executed?
$ export foo=’echo world; () { echo hello;}’
$ bash
No. The vulnerability exists only when the variable value starts with '() {'. If not,
it's considered a regular string and foo will be available as a variable in the child
process.
6. How do user inputs get into a remote a CGI program (written in Bash)
in the form of environment variables?
Webservers like Apache pass on client header information, such as User-Agent,
as environment variables to the CGI programs they invoke. By manually setting
the User-Agent field, for instance, we can ensure there's an environment variable
with a value chosen by us available on the remote machine.
8. (*) Why was this mistake made? And what lesson did you learn from
this mistake?
This mistake was likely due to a lack of input validation and sanitization on the part of
the CGI programs that were vulnerable to the Shellshock attack. The developers may
have assumed that the User-Agent field would only contain a string identifying the user's
browser or operating system, and not a command to be executed.
The lesson to be learned from this mistake is to always validate and sanitize user input
and to treat all input as untrusted. This includes headers and fields in HTTP requests,
as demonstrated by the Shellshock attack. By properly checking and restricting the
input, developers can prevent attackers from injecting malicious commands or exploiting
unintended vulnerabilities in their code.
http://www.example.com/myprog.cgi?name=value
Can we put our malicious function definition in the value field of the
above URL, so when this value gets into the CGI program myprog.cgi,
the Shellshock vulnerability can be exploited?
1. Exploiting Shellshock in CGI Programs:
○ CGI (Common Gateway Interface) programs are used to generate
dynamic content on web servers.
○ If a CGI script is written in Bash or launches Bash subshells, it can be
vulnerable to Shellshock.
○ Attackers can exploit this vulnerability by sending specially crafted input
via the URL, as you mentioned:
http://www.example.com/myprog.cgi?name=value
○
○ In this case, the value parameter could contain a malicious function
definition or arbitrary Bash commands.
○ When the CGI program processes this input, it may inadvertently execute
the attacker’s code, leading to potential system compromise3.
2. Mitigation and Protection:
○ To protect against Shellshock:
■ Update Bash: Ensure that your system is running an updated
version of Bash that addresses the vulnerability.
■ Sanitize Inputs: Properly validate and sanitize all user inputs,
especially those passed to CGI scripts.
■ Patch Management: Regularly apply security patches to your
servers.
■ Security Audits: Conduct security audits to identify and address
vulnerable systems.
Remember that Shellshock is an old but persistent threat. Organizations should remain
vigilant and take necessary precautions to safeguard their systems against this
vulnerability.
11. Please describe how you would do the following: run the /bin/cat
program on Machine 1; the program takes its input from Machine 2,
and print out its output to Machine 3.
Machine2:
$ nc -l 7070
Machine3:
$ nc -l 7070
Machine 1:
$ /bin/cat < /dev/tcp/Machine2/7070 > /dev/tcp/Machine3/7070
The program forks a child process, and executes the /bin/ls program
using /bin/sh, which is a symbolic link to /bin/bash. The program is
executed as the following. Explain what the output of the program will
be and why.
$ gcc prog.c -o prog
$ export foo=’() { echo hello; }; echo world;’
$ ./prog
The output of the program will be:
parent child hello world
Here's why:
Note that the output of the /bin/ls command is not seen in the output, as the
function defined in the environment variable foo takes precedence and is
executed instead.
13.
Let’s make a change to the code in Problem 3.12.. We change the code in Line
following. Please redo Problem 3.12. with this change made
execve(args[0], &args[0], environ);
The Shellshock vulnerability is exploitable in the CGI program (test.cgi) but not in
the PHP program (test.php) when invoked as described in the question.
Explanation:
The Shellshock vulnerability affects the bash shell and allows an attacker to
inject arbitrary commands in the environment variables, which are then executed
by the bash shell. The vulnerability is exploited when a function definition is
placed in an environment variable, followed by a command to execute that
function. This can be triggered by using a specially crafted HTTP request header,
as in the example provided.
In the case of the PHP program (test.php), the system() function executes the
/bin/ls command directly and not in a bash shell. Thus, the environment variables
are not processed by the bash shell, and the Shellshock vulnerability cannot be
exploited.
In the case of the CGI program (test.cgi), the /bin/ls command is invoked in a
bash shell, as indicated by the shebang (#!/bin/sh) and the presence of the bash
shell at the beginning of the line (/bin/ls -1). This means that if the environment
variables are manipulated to exploit the Shellshock vulnerability, it could be
executed by the bash shell.
1. How are the addresses decided for the following variables a and x, i.e.,
during the runtime, how does the program know the address of these two
variables?
void foo(int a) {
int x; }
a will be allocated on the stack, since it is a parameter
—-
a sẽ được cấp phát (allocated) tại stack, vì a là một tham số (parameter)
x sẽ được cấp phát (allocated) tại stack, vì x là một giá trị cục bộ (local variable)
2. In which memory segments are the variables in the following code located?
int i = 0; //i: data segment, đo đây là biến được đã được khởi tạo
// ptr: stack
//*ptr: heap, cung cấp không gian để có thể cung cấp bộ nhớ linh hoạt
int j; //stack,
static int y; //BSS segment, chứa giá trị tĩnh, chưa khởi tạo
}
Data segment: store global/static variable initialized by the programmer
3. Please draw the function stack frame for the following C function.
int bof(char *str) {
char buffer[24]; strcpy(buffer,str); return 1;
}
- i is in the data segment since it's a global variable
- the *ptr pointer is on the stack, however the value it's pointing to is on the heap.
str
Return address
Buffer[23]
Buffer[0]
strcpy(c, str);
void foo(){
bar("overflow");
When say, func1() call func2(), the call stack of func2 exits on the top of func1’s call
stack. So we can prevent the return address of func1 getting modified, but a more
calculated attack can override func2’s return address, leading to the similar results.
5. In the buffer overflow example shown in Listing 4.1, the buffer overflow
occurs inside the strcpy() function, so the jumping to the malicious code
occurs when strcpy() returns, not when foo() returns. Is this true or false?
Please explain.//True. Buffer overflow affects the stack frame during strcpy(), enabling
control over the return address upon strcpy() completion.The answer is false. Yes, the
buffer overflow occurs in strcpy, but what the buffer overflow does is override the return
address of the foo function, so the jumping to the malicious code occurs when foo()
returns, not when strcpy() returns.Câu trả lời là sai. Đúng là buffer overflow xuất hiện ở
strcpy nhưng thực tế BF làm là ghi đè (override) địa chỉ trả về(return address) của
hàm foo(). Điều đó nghĩa là việc chuyển hướng tới mã độc sẽ chỉ xuất hiện khi foo()
trả về, không phải khi strcpy() trả về.
fixed version:
{
char buffer = (char ) malloc(size);
strncpy(buffer, str,size-1);
return 1;
}Yes, buffer is now located on the heap and not on the stack, and you can’t reach the
stack by overflowing something on the heap.
7. Several students had issue with the buffer overflow attack. Their badfile
was constructed properly where shell code is at the end of badfile, but when
they try different return addresses, they get the following observations. Can
you explain why some addresses work and some do not?
buffer address : 0xbffff180
case 1 : long retAddr = 0xbffff250 -> Able to get shell access case 2 : long
retAddr = 0xbffff280 -> Able to get shell access case 3 : long retAddr =
0xbffff300 -> Cannot get shell access
case 4 : long retAddr = 0xbffff310 -> Able to get shell access case 5: long
retAddr = 0xbffff400 -> Cannot get shell access
buffer address: 0xbffff180
The return address has a zero byte, therefore strcpy will stop copying the rest of bad file
content, including the malicious code.
8. The following function is called in a privileged program. The argument str
points to a string that is entirely provided by users (the size of the string is up
to 300 bytes). When this function is invoked, the address of the buffer array
is 0xAABB0010, while the return address is stored in 0xAABB0050. Please
write down the string that you would feed into the program, so when this
string is copied to buffer and when the bof() function returns, the privileged
program will run your code. In your answer, you don’t need to write down
the injected code, but the offsets of the key elements in your string need to be
correct. Note: there is a trap in this problem; some people may be lucky and
step over it, but some people may fall into it. Be careful.
int bof(char *str) {
char buffer[24]; strcpy(buffer,str); return 1;
}
the offset to reach the return address from the buffer is 64 bytes (AABB0050 –
AABB0010 = 40{hex} = 4*16^1 + 0*16^0 = 64 {decimal})
- we need to do some padding to fill the buffer completely, so need to fill in data for
those 24 bytes. We can do this by putting in garbage data, like a bunch of As
- 64-24=40 bytes used up so far
- so we got to the end of the buffer, now we gotta add 40 more bytes of filler to get to
the return address. Like before just put in a bunch of As
- now we got to where the return address is suppose to be, now we insert the address
to the code we want to inject
- after putting in the address we want we need to put in a null terminator or a 0
- is an OS approach
- so every time the code is loaded in memory, the stack addresses change
- makes it harder to guess the stack address in memory using the debugger
- also makes it harder to guess the ebp address( the base pointer location or the base
of the stack currently) as as the address of your target code
10. To write a shellcode, we need to know the address of the string "/bin/sh".
If we have to hardcode the address in the code, it will become difficult if
ASLR is turned on. Shellcode solved that problem without hardcoding the
address of the string in the code. Please explain how the shellcode in exploit.c
(Listing 4.2) achieved that.
shellcode= (
"\x31\xc0" # xorl %eax,%eax
"\x50" # pushl %eax
"\x68""//sh" # pushl $0x68732f2f
"\x68""/bin" # pushl $0x6e69622f
"\x89\xe3" # movl %esp,%ebx
"\x50" # pushl %eax
"\x53" # pushl %ebx
"\x89\xe1" # movl %esp,%ecx
"\x99" # cdq
"\xb0\x0b" # movb $0x0b,%al
"\xcd\x80" # int $0x80
).encode(' latin-1')
Shellcode searches memory for specific patterns or APIs to locate resources like
/bin/sh, avoiding reliance on hardcoded addresses.“/bin/sh” is pushed onto the stack,
together with a zero byte marking the end of the string. At that time, stack pointer esp is pointing
to the address of the string.
“/bin/sh” được đẩy lên ngăn xếp, cùng với byte 0 đánh dấu kết thúc chuỗi. Khi đó, con trỏ
ngăn xếp esp đang trỏ đến địa chỉ của chuỗi.
11. When you construct the attack string in Problem 8, you have many
choices when deciding what value to put in the return address field. What is
the smallest value that you can use?11. When you construct the attack string in Problem
8, you have many choices when deciding what value to put in the return address field. What is
the smallest value that you can use?
=> t = 45
=> 0xAABB0104
The malicious code is of 24 bytes, located at the end of 300 byte buffer.
The return address can be any address in the NOP range, that does not contain a zero byte. A
safe choice is 0xAABBCC10 + 100 + 8 + 4 = 0xAABBCC80
Rải 108 bytes đầu + 4 bytes với 4 bytes địa chỉ trả về, là 28 địa chỉ trả về (return address
là 4 byte => 112 / 4 = 28 return address)
Địa chỉ trả về có thể là bất cứ địa chỉ nào trong khoảng NOP mà không chứa byte có giá trị
0. Một lựa chọn an toàn là 0xAABBCC10 + 100 + 8 + 4 = 0xAABBCC80
*khoảng NOP (NOP range): là một sequence (chuỗi) của những lệnh (instructions) không
thực thi (No operation instruction).