Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Midterm 3-4

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 17

I.

ShellShock

1. When a shell variable containing a shell function definition is passed


down to a child process as an environment variable, what is going to
happen to the function definition?

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.

when a shell variable containing a shell function definition is


passed down to a child process as an environment variable, the
function definition will not be recognized or executed in the child
process.

Here's why:

Environment variables are used to pass information from a parent


process to a child process during process creation.
When a child process is created, it inherits a copy of the parent
process's environment variables, including any shell variables that
contain shell function definitions.
However, the child process does not inherit the parent process's
shell functions themselves, only their definitions as strings.
The child process's shell does not automatically parse or execute
these strings as function definitions, so any shell functions defined
in the parent process will not be available in the child process.
In summary, while the child process can access the string
representation of the shell function definition through the inherited
environment variable, it cannot use the function directly as it
would in the parent process. The child process would need to define
the function itself in order to use it.
2. Assume a Bash program defines a shell function, exports it, and then
starts a child process that also runs Bash. Please explain how this
function defined in the parent Bash becomes a function in the child
Bash.
When the parent shell creates a process, it passes each exported function as an
environment variable. When the child process runs bash (or the child process
itself is bash), it'll parse the environment variable and convert it back to a
function. This happens because a child process gets a copy of the parents
environment variables.

3. Write a Bash function definition that tries to exploit the Shellshock


vulnerability.
[09/23/2018 15:40] seed@ubuntu:~$ export foo='() { echo Hello World; }; rm -rf /'

[09/23/2018 15:40] seed@ubuntu:~$ bash

rm: it is dangerous to operate recursively on `/'

rm: use --no-preserve-root to override this failsafe

[09/23/2018 15:40] seed@ubuntu:~$

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.

[09/23/2018 15:47] seed@ubuntu:~$ export foo='echo world; () { echo hello;}'

[09/23/2018 15:47] seed@ubuntu:~$ bash

[09/23/2018 15:47] seed@ubuntu:~$ foo

foo: command not found

[09/23/2018 15:47] seed@ubuntu:~$ echo $foo

echo world; () { echo hello;}

5. For the Shellshock vulnerability to be exploitable, two conditions need


to be satisfied. What are these two conditions?
Two conditions are needed to exploit the vulnerability: 1) The
target process should run bash 2) The target process should get
untrusted user inputs via environment variables

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.

7. Instead of using a function definition in the Shellshock attack against


CGI programs, can we directly put shell commands inside the User-
Agent field, so when Bash is triggered, the shell command can be
executed?
No. The bash vulnerability exists because it looks for the string '() {' at the
beginning of the value of the environment variable, and if it's a match, it
considers it a function and proceeds to parse it. Without looking like a function
definition, bash will treat it as a simple string and not run the commands.

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.

9. There is another way to send inputs to a CGI program. That is to attach


the input in the URL. See the following example.

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.

10. We run "nc -l 7070" on Machine 1 (IP address is 10.0.2.6), and


we then type the following command on Machine 2. Describe what is
going to happen?
$ /bin/cat < /dev/tcp/10.0.2.6/7070 >&0
The nc -l 7070 will listen on port 7070 for incoming connections. The
/bin/cat command is quite weird. < /dev... will accept input from the remote
machine, but will output it back to STDIN, which is this case is the remote
machine.

So anything typed in Machine 1 will be echoed back on screen.

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

12. Consider the following program:

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:

1. The program forks a child process.


2. In the parent process, the printf("parent\n") statement is executed, and
then the program returns 0.
3. In the child process, the printf("child\n") statement is executed, and
then the program tries to execute the /bin/sh command with the -c flag,
which allows for running a command string. The command string is
/bin/ls.
4. But before the /bin/ls command is executed, the environment variable foo
is defined with the export command in the terminal. This command sets up
a function that echoes "hello" and then echoes "world".
5. Since /bin/sh is a symbolic link to /bin/bash, the function defined in the
environment variable foo will be executed when /bin/sh is executed.
6. As a result, "hello" and "world" will be printed to the console.

Therefore, the output of the program will be:

parent child hello world

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);

14. Consider a PHP program running as Apache module, and a CGI


program.
Both programs invoke /bin/ls command in a new shell process (/bin/sh
points to /bin/bash). If the programs are invoked as the following,
please explain the difference in effect of the Shellshock vulnerability
on these two cases. What conditions are necessary to exploit shellshock
in either case?
$ curl -A "() { echo hello; }; echo world;" http://localhost/test.php
$ curl -A "() { echo hello; }; echo world;" http://localhost/test.cgi

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.

However, for the Shellshock vulnerability to be exploited in either case, it is


necessary to have control over the environment variables that are passed to the
bash shell. In the case of the CGI program, the environment variables come from
the HTTP request headers, which are typically controlled by the user-agent (e.g.,
the web browser). Therefore, the user-agent must be manipulated to inject the
malicious environment variable that exploits the Shellshock vulnerability.

In summary, the Shellshock vulnerability is not exploitable in the PHP program


(test.php), but it could be exploited in the CGI program (test.cgi) if the
environment variables are manipulated to inject the malicious environment
variable that exploits the Shellshock vulnerability.

II. Buffer Overflow

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

x will be allocated on the stack since it is an local variable

—-
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)

Địa chỉ của a: a = ebp + 8

Địa chỉ của x: x = ebp - 4

2. In which memory segments are the variables in the following code


located?
int i = 0;
void func(char *str) {
char *ptr = malloc(sizeof(int)); char buf[1024];
int j;
static int y;
}

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

void func(char *str) { //str: stack segment

char *ptr = malloc(sizeof(int));

// ptr: stack

//*ptr: heap, cung cấp không gian để có thể cung cấp bộ nhớ linh hoạt

(dynamic memory allocation)

char buf[1024]; //stack

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

Stack: chứa giá trị cục bộ trong hàm

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.

- buf is allocated on the stack

- j is located on the stack

- since y is static, it's in the BSS segment

str

Return address

Previous Frame Pointer

Buffer[23]

Buffer[0]

4. A student proposes to change how the stack grows. Instead of growing


from high address to low address, the student proposes to let the stack grow
from low address to high address. This way, the buffer will be allocated
above the return address, so overflowing the buffer will not be able to affect
the return address. Please comment on this proposal. Altering stack growth won't
necessarily prevent buffer overflow attacks; more sophisticated exploits can still
manipulate memory beyond the return address.This wouldn't defeat the problem.you
could still override the return address of the next stack frame when this function call
other function. For example, say you have functions:

void bar(char* str){


char c[7];

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ề.

6. The buffer overflow example was fixed as below. Is this safe ?


int bof(char *str, int size) { char buffer = (char*) malloc(size); strcpy(buffer,
str); return 1; }No
- It can still be possible to pass a value of n that is not the size of the string passed in

- A fix for this problem would be to use strncpy

fixed version:

int bof(char *str, int size)

{
char buffer = (char ) malloc(size);

strncpy(buffer, str,size-1);

buffer[size-1]="\0"; // makes sure we have a null terminator

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

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

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

9. Why does ASLR make buffer-overflow attack more difficult?ASLR


randomizes memory addresses, making it harder for attackers to predict code or data
locations, complicating buffer overflow exploits.- ASLR= Address Space Layout
Resolution

- is an OS approach

- ASLR randomizes the start location of the stack

- 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?

0xAABB0050 + 4.t > 0xAABB0100

=> t = 45

=> 0xAABB0104

- so like 0xAABB0010+24= 0xAABB0028

12. The following function is called in a remote server program. The


argument str points to a string that is entirely provided by users (the size of
the string is up to 300 bytes). The size of the buffer is X, which is unknown
to us (we cannot debug the remote server program). However, somehow we
know that the address of the buffer array is 0xAABBCC10, and the distance
between the end of the buffer and the memory holding the function’s return
address is 8. Although we do not know the exact value of X, we do know that
its range is between 20 and 100.
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 server
program will run your code. You only have one chance, so you need to
construct the string in a way such that you can succeed without knowing the
exactly value of X. 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.
int bof(char *str) {
char buffer[X]; strcpy(buffer,str); return 1;
}
Spray the first 108 + 4 bytes with 4 bytes of the return address, i.e 28 return addresses

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)

Mã độc có 24 bytes, nằm ở cuối của buffer 300 bytes

Đị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).

You might also like