From 70c56ae236741e108919f181c2f60f8cf4e0bbd8 Mon Sep 17 00:00:00 2001 From: Ori Date: Thu, 27 Apr 2023 15:39:06 +0300 Subject: [PATCH 1/4] Added hebrew translation for article 1.6 --- 1/he/6.html | 263 +++++++++++++++++++++++++++++++++++++++ 1/he/index.html | 38 +++--- 1/txt/1.txt. | 324 ------------------------------------------------ 3 files changed, 282 insertions(+), 343 deletions(-) create mode 100644 1/he/6.html delete mode 100644 1/txt/1.txt. diff --git a/1/he/6.html b/1/he/6.html new file mode 100644 index 0000000..b016a7e --- /dev/null +++ b/1/he/6.html @@ -0,0 +1,263 @@ + + +tmp.0ut + + + + +
+
+                                                      ┐───────────────────────┌
+                                                      │       ▄▄▄▄▄ ▄▄▄▄▄ ▄▄▄▄▄
+                                                      │       █   █ █ █ █   █ │
+                                                      │       ▀▀▀▀█ █ █ █   █ │
+                                                      │     ▄     █ █   █   █ │
+                                                      │ ▄▄▄▄▄                 │
+                                                      │ █   █                 │
+                                                      │ █   █                 │
+                                                      │ █▄▄▄█                 │
+                                                      │ ▄   ▄                 │
+                                                      │ █   █                 │
+                                                      │ █   █                 │
+                                                      │ █▄▄▄█                 │
+                                                      │ ▄▄▄▄▄                 │
+                                                      │   █                   │
+דיסאסמבלי-שגוי פולימורפית                             │   █                   │
+~ S01den                                              ┘───█───────────────────└
+
+נכתב באהבה ע"י S01den, מהצוות של tmp.out !
+mail: S01den@protonmail.com
+
+[ תורגם ע"י Lit3r4lly ]	
+
+--- הקדמה ---
+
+כשכתבתי את [0]Lin32.Bakunin, תהיתי לעצמי איך לעשות את זה יותר מעניין 
+מסתם וירוס שכתוב ב-MIPS ומדפיס קצת שטויות. אני פשוט רציתי לעצבן רברסרים.
+ואז נזכרתי בטכניקת ה-False-Disassembly שמימשתי בחלק מה-crackme's שלי.
+
+בגלל שפולימורפיזם זה מגניב, רציתי להבין אם זה אפשרי ליצור משהו מעניין בעזרת ערבוב של זה יחד עם
+טכניקת ה-False-Disassembly.
+
+התשובה היא כן, וקראתי לשיטה הזו (אני לא יודע אם זו טכניקה מקורית שלי או לא), שיטת
+ה-"דיסאסמבלי-שגוי פולימורפית" או בפשטות "פולימורפיזם מזוייף".
+
+--- איך False-Disassembly עובד? ---
+
+הטכניקה הזו היא די פשוטה להבנה ולמימוש, ואני גיליתי עליה במסמך המפורסם של [1]Silvio Cesare על
+טכניקות anti-debugging ורברסינג בלינוקס.
+פשוט צריך לשים כמה בייטים רנדומליים שבד"כ מייצגים התחלה של הוראה מסויימת (Opcode) לפני קטע הקוד,
+כמו בדוגמה הבאה:
+
+
+-------------------- נחתך-כאן --------------------
+hey:                      hey:
+   xor %rbx, %rbx             .ascii "\x48\x31"
+   jmp yo            ====>     xor %rbx, %rbx
+                               jmp yo
+---------------------------------------------------
+
+עכשיו, אם נסתכל על שני קטעי הקוד שעברו disassemble, אנחנו נקבל משהו כזה (radare2 מה לעזעזאל?):
+
+-------------------- נחתך-כאן --------------------
+;-- hey:
+0x00401002      4831db         xor rbx, rbx
+0x00401005      eb02           jmp 0x401009
+
+                     ||
+                     \/
+;-- hey:
+0x00401002      48314831       xor qword [rax + 0x31], rcx
+0x00401006      dbeb           fucomi st(3)
+0x00401008      026631         add ah, byte [rsi + 0x31]
+
+---------------------------------------------------
+
+מדוע הדיסאסמבלר מתנהג בצורה הזו?
+
+ובכן, \x48\x31 הם בד"כ ייצוג של ההתחלה של הוראת [2]xor, והבייטים שבאים לאחר מכן מייצגים לרוב את
+האוגרים שאיתם האופרציה עובדת.
+
+אז למעשה הבייטים ה"מאתחלים" הללו שהוספנו נדבקים לבייטים העוקבים, שהם למעשה בעצמם בייטים "מאתחלים", וכך
+הדיסאסמבלר מפרש את אותם בייטים מאתחלים באמת, כבייטים המייצגים את הרגיסטרים ובגלל זה מופיע לנו זבל במקום ההוראות הרצויות.
+
+לכן, כדי שנוכל להריץ קוד שבנוי בצורה שכזו, אנחנו חייבים לקפוץ מעל הבייטים שהוספנו.
+זה אמור להיות משהו כזה:
+
+
+-------------------- נחתך-כאן --------------------
+_start:
+jmp hey+2
+
+hey:
+   .ascii "\x48\x31"
+   xor %rbx, %rbx
+   jmp yo
+---------------------------------------------------
+
+
+--- הקוד המלא ---
+
+עכשיו, דמיינו שאתם יכולים רנדומלית לשנות את כל הבייטים הללו שמייצרים את ה-false-disassembly בכל
+אופרציה, וכך גם הקוד שעבר disassembly ישתנה גם ולכן הרברסר
+שיחקור את הקוד, יחשוב שהוא פולימורפי בזמן שרק מספר בייטים בודדים שונו.
+
+וכעת, ללא דיחוי נוסף, הקוד המלא.
+
+
+----------- נחתך כאן -----------
+# build cmd: as Linux.FakePolymorphism.asm -o fakePoly.o ; ld fakePoly.o -o fakePoly
+
+# this code is a fake polymorphic example, feel free to try/use/whatever it!
+# It grabs itself its code, modify the fake-disassembly bytes and put the result
+# on the stack.
+
+.text
+  .global _start
+
+_start:
+jmp true_start+2 # jump over the fake-disassembly bytes
+
+true_start:
+.ascii "\x48\x31"  # fake-disassembly bytes
+xor %rbx, %rbx
+jmp get_code+2 # jump over the fake-disassembly bytes
+
+get_code:
+  .ascii "\x66\x31"  # fake-disassembly bytes
+  call get_rip
+  sub $0x10 ,%rax # 0x10 is the number of bytes between _start abd this instruction
+  movb (%rax,%rbx), %al
+  movb %al, (%rsp,%rbx)
+  inc %rbx
+  cmp $0x54, %rbx  # 0x54 is the total size of this code
+  jne get_code+2
+
+  # Pseudo RNG thanks to the time stamp counter
+  rdtsc
+  xor $0xdead, %rax
+  mov %ax, 2(%rsp)
+  xor $0xbeef, %rdx
+  mov %ax, 9(%rsp)
+
+  mov $60, %rax
+  mov $0, %rdi
+  syscall # sys_exit
+
+get_rip:
+  mov (%rsp), %rax
+  ret
+----------------------------
+
+--- סיכום ---
+
+אני מקווה שנהנתם מהמאמר הזה ושתנסו לממש את הטכניקה הזו בוירוסים והcrackme's שלכם!
+
+ביחד עם sblip, כתבנו וירוס פולימורפי  (Lin64.Eng3ls, תעיפו מבט על המאמר והקוד !) שמשתמש בטכניקה
+הזו בשביל לערפל את הקוד של המפענח של עצמו.
+
+הקוד של המפענח:
+
+
+------- נחתך-כאן -------
+  pop rcx
+  jmp jmp_over+2
+  jmp_over:
+    db `\x48\x31` ; false disassembly
+    mov al,0x00
+    xor rdx, rdx
+
+  decoder:
+    jmp jmp_over2+2
+
+    jmp_over2:
+      db `\xb8\xd9` ; false disassembly
+      mov dl, byte [r12+rdi]
+      cmp rdi, STUB_SIZE-1
+      jna no_decrypt
+
+      jmp jmp_over3+2
+      jmp_over3:
+        db `\x48\x81` ; false disassembly
+        xor dl, al
+
+  no_decrypt:
+    mov byte [rbx+rdi], dl
+    inc rdi
+  loop decoder
+-------------------------
+
+והנה מספר מפענחים שהבאתי מבינארים זדוניים שונים שעברו [3]disassemble, בוא נראה את הטריק בפעולה:
+
+1. 
+  0x0c003f46      59             pop rcx                 
+  0x0c003f47      eb02           jmp 0xc003f4b           
+  0x0c003f49      00d6           add dh, dl              
+  0x0c003f4b      b06d           mov al, 0x6d            
+  0x0c003f4d      4831d2         xor rdx, rdx            
+  0x0c003f50      eb02           jmp 0xc003f54           
+  0x0c003f52      1aca           sbb cl, dl              
+  0x0c003f54      418a143c       mov dl, byte [r12 + rdi]
+  0x0c003f58      4881ff870000.  cmp rdi, 0x87           
+  0x0c003f5f      7606           jbe 0xc003f67           
+  0x0c003f61      eb02           jmp 0xc003f65           
+  0x0c003f63      c0d630         rcl dh, 0x30            
+  0x0c003f66      c28814         ret 0x1488              
+  0x0c003f69      3b48ff         cmp ecx, dword [rax - 1]
+  0x0c003f6c      c7             invalid                 
+  0x0c003f6d      e2e1           loop 0xc003f50          
+
+2.
+  0x0c003fe6      59             pop rcx
+  0x0c003fe7      eb02           jmp 0xc003feb
+  0x0c003fe9      ce             invalid
+  0x0c003fea      0ab0a34831d2   or dh, byte [rax - 0x2dceb75d]
+  0x0c003ff0      eb02           jmp 0xc003ff4
+  0x0c003ff2      39cb           cmp ebx, ecx
+  0x0c003ff4      418a143c       mov dl, byte [r12 + rdi]
+  0x0c003ff8      4881ff870000.  cmp rdi, 0x87
+  0x0c003fff      7606           jbe 0xc004007
+  0x0c004003      0e             invalid
+  0x0c004004      0a30           or dh, byte [rax]
+  0x0c004006      c28814         ret 0x1488
+  0x0c004009      3b48ff         cmp ecx, dword [rax - 1]
+  0x0c00400c      c7             invalid
+  0x0c00400d      e2e1           loop 0xc003ff0
+
+התוצאות שונות מאוד מהקוד המקורי.
+
+--- הערות ורפרנסים ---
+
+[0] https://vx-underground.org/papers/VXUG
+      /Exclusive/Bakounin/Writing_virus_in_MIPS_assembly_for_fun.txt
+[1] http://www.ouah.org/linux-anti-debugging.txt // Silvio המסמך של
+[2] https://www.felixcloutier.com/x86/xor
+[3] radare2 עם 
+
+
diff --git a/1/he/index.html b/1/he/index.html index b55079b..3370862 100644 --- a/1/he/index.html +++ b/1/he/index.html @@ -33,27 +33,27 @@ │ █▄▄▄█ │ │ ▄▄▄▄▄ │ ┐───────────────────────────────────────────────────────────│ █ │ -│ tmp.0ut גיליון 1 - אפריל 2021 │ █ │ +│ tmp.0ut גיליון 1 - אפריל 2021 │ █ │ │ תוכן ┘── █───────────────────└ │ │ -│ 1.0 הקדמה ‏........................................................‏ צוות tmp.0ut │ -│ 1.1 בייטים מתים ‏................................................... xcellerator │ -│ 1.2 מימוש שיטת הדבקה דרך PT_NOTE ב-x64 assembly ‏.........................‏ sblip │ -│ 1.3 מזריק ELF בטכניקת PT_NOTE ל-PT_LOAD, ב-Rust ‏.........................‏ d3npa │ -│ 1.4 PT_NOTE Disinfector ב-Python ‏.....................................‏ manizzle │ -│ 1.5 פאזינג ל-Radare2 בשביל חולשות בכ-30 שורות קוד ‏...........‏ Architect, s01den │ -│ 1.6 The Polymorphic False-Disassembly Technique ‏........................‏ s01den │ -│ 1.7 Lin64.Eng3ls: טכניקות אנטי-RE בוירוס לינוקסי ‏................‏ s01den, sblip │ -│ 1.8 Linux.Midrashim.asm ‏...................................................‏ TMZ │ -│ 1.9 טעינת LKM בזיכרון ‏...............................................‏ netspooky │ -│ 1.10 Linux SHELF Loading ‏....................................‏ ulexec, Anonymous_ │ -│ 1.11 חזרה לנקודת הכניסה המקורית למרות PIE ‏...............................‏ s01den │ -│ 1.12 כתיבת וירוסים ב-MIPS Assembly לכיף (ובלי Profit) ...................‏ s01den │ -│ 1.13 ראיון: herm1t ‏...............................................‏ tmp.0ut Staff │ -│ 1.14 Linux/Retaliation - נעלם ב-360 שניות ‏...............................‏ qkumba │ -│ 1.15 Linux.Nasty.asm ‏.......................................................‏ TMZ │ -│ 1.16 Linux.Precinct3.asm ‏.............................................‏ netspooky │ -│ 1.17 עולמות Underground ‏.................................................‏ s01den │ +│ 1.0 הקדמה ........................................................ צוות tmp.0ut │ +│ 1.1 בייטים מתים ................................................... xcellerator │ +│ 1.2 Implementing the PT_NOTE Infection Method In x64 Assembly ........... sblip │ +│ 1.3 PT_NOTE To PT_LOAD ELF Injector In Rust ............................. d3npa │ +│ 1.4 PT_NOTE Disinfector In Python .................................... manizzle │ +│ 1.5 Fuzzing Radare2 For 0days In About 30 Lines Of Code ..... Architect, s01den │ +│ 1.6 דיסאסמבלי-שגוי פולימורפית .......................................... s01den │ +│ 1.7 Lin64.Eng3ls: Some Anti-RE Techniques In A Linux Virus ...... s01den, sblip │ +│ 1.8 Linux.Midrashim.asm ................................................... TMZ │ +│ 1.9 In-Memory LKM Loading ........................................... netspooky │ +│ 1.10 Linux SHELF Loading .................................... ulexec, Anonymous_ │ +│ 1.11 Return To Original Entry Point Despite PIE ......................... s01den │ +│ 1.12 Writing Viruses In MIPS Assembly For Fun (And No Profit) ........... s01den │ +│ 1.13 ראיון: herm1t ............................................... tmp.0ut Staff │ +│ 1.14 GONE IN 360 SECONDS - Linux/Retaliation ............................ qkumba │ +│ 1.15 Linux.Nasty.asm ....................................................... TMZ │ +│ 1.16 Linux.Precinct3.asm ............................................. netspooky │ +│ 1.17 Underground Worlds ................................................. s01den │ │ │ ┘──────────────────────────────────────────────────────────────────────────────────└ diff --git a/1/txt/1.txt. b/1/txt/1.txt. deleted file mode 100644 index c899064..0000000 --- a/1/txt/1.txt. +++ /dev/null @@ -1,324 +0,0 @@ - _ .-') _ ('-. ('-. _ .-') _ .-. .-') .-') _ ('-. .-') -( ( OO) ) _( OO) ( OO ).-.( ( OO) ) \ ( OO ) ( OO) ) _( OO) ( OO ). - \ .'_ (,------./ . --. / \ .'_ ;-----.\ ,--. ,--./ '._(,------.(_)---\_) - ,`'--..._) | .---'| \-. \ ,`'--..._) | .-. | \ `.' / |'--...__)| .---'/ _ | - | | \ ' | | .-'-' | | | | \ ' | '-' /_).-') / '--. .--'| | \ :` `. - | | ' |(| '--.\| |_.' | | | ' | | .-. `.(OO \ / | | (| '--. '..`''.) - | | / : | .--' | .-. | | | / : | | \ || / /\_ | | | .--' .-._) \ - | '--' / | `---.| | | | | '--' / | '--' /`-./ /.__) | | | `---.\ / - `-------' `------'`--' `--' `-------' `------' `--' `--' `------' `-----' - ~ xcellerator - -Ahoy, fellow ELF devotees! In this article, I want to introduce a small library I've been working -on called LibGolf. It started out as simply a vehicle for better understanding the ELF and program -headers, but has since spun into something reasonably practical. It makes is very easy to generate -a binary consisting of an ELF header, followed by a single program header, followed by a single -loadable segment. By default, all the fields in the headers are set to sane values, but there's a -simple way to play with these defaults - and that's what this article is all about! I'm going to -demonstrate how I used LibGolf to enumerate precisely which bytes are necessary and which are -ignored by the Linux loader. Fortunately, it turns out that the loader is one of the least picky -parsers among the standard Linux toolkit. Before we're through, we'll see several popular static -analysis tools crumble before our corrupted ELF, while the loader continues to merrily load and -jump to our chosen bytes. - -+---------------------------+ -|--[ Introducing LibGolf ]--| -+---------------------------+ - -A while back, I'd been playing with writing ELFs by hand in NASM. While this was fun for a while -(and certainly has it's benefits), I realised that I was missing out on all the fun that C structs -have to offer. In particular, as I'm sure many readers will no doubt be aware, , is -packed full of fun things like `Elf64_Ehdr` and `Elf32_Phdr` ripe for declaring. - -Not wanting such helpful headers to go to waste, I elected to take them, and put them to good use. -From these efforts, came libgolf.h, a libary that makes it easy to throw shellcode into a -functioning executable. I know what you're thinking - "this just sounds like a terrible linker!", -and you might be right. However, what's nice here is that you can easily modify the headers *before* -the binary is built. - -Let's take a look at how this works. If you want to play along at home, you can find the source code -for all of this at [0]. You can find the code in this article under 'examples/01_dead_bytes'. The -basic setup needs two files; a C source file and a shellcode.h. As far as shellcode goes, I like to -go with the old faithful 'b0 3c 48 31 ff 0f 05', which disassembles to: - - mov al, 0x3c @ b0 3c - xor rdi, rdi @ 48 31 ff - syscall @ 0f 05 - -(Yes - calling this "shellcode" is pushing things a bit!) - -Essentially, it just calls exit(0). This is nice because we can easily check that these bytes -successfully executed with the shell expansion $?. - -Throw this or some other shellcode (but make sure it's PIC - there's no support for relocatable -symbols yet!) into a buffer called buf[] in shellcode.h and jump back to the C file. If you just -wanted to get a binary that executes your shellcode, then this is all you need: - - #include "libgolf.h" - #include "shellcode.h" - - int main(int argc, char **argv) - { - INIT_ELF(X86_64,64); - - GEN_ELF(); - return 0; - } - -Compiling this and running the resulting executable will provide you with a .bin file - this is -your shiny new ELF! Pretty simple, right? Simplicity is often accompanied by the dull, as is the -case here, so let's do something more interesting! - -Before going on, it's worth explaining what these two macros are doing behind the scenes. First off, -INIT_ELF() takes two arguments, the ISA and the architecture. Currently, LibGolf supports X86_64, -ARM32, and AARCH64 as valid ISAs and either 32 or 64 for the architecture. It first sets up some -internal bookkeeping structs, and decides whether to use the Elf32_* or Elf64_* objects for the -headers. It also automatically assigns pointers to the ELF and program headers, called ehdr and -phdr respectively. It is these that we will use to easily modify the fields. Aside from that, it -also copies the shellcode buffer over, and populates the ELF and program headers before calculating -a sane entry point. Now comes GEN_ELF(), which just prints some nice stats to stdout and then writes -the appropriate structs to the .bin file. The name of the .bin is determined by argv[0]. - -So, after we've used the INIT_ELF() macro, we have ehdr and phdr available to dereference. Suppose -we wanted to modify the e_version field of the ELF header. All we need to do is add a single line: - - #include "libgolf.h" - #include "shellcode.h" - - int main(int argc, char **argv) - { - INIT_ELF(X86_64); - - // Set e_version to 12345678 - ehdr->e_version = 0x78563412; - - GEN_ELF(); - return 0; - } - -Another quick compile and execute, and you'll have another .bin file waiting for you. Taking a look -at this file in xxd, hexyl, or your favourite bin-manipulator of choice, you'll see a pretty little -'12 34 56 78' peeking back at you starting at offset 0x14. Wasn't that easy? - -To make things move a little faster, I like to use the following Makefile: - - .PHONY golf clean - - CC=gcc - CFLAGS=-I. - PROG=golf - - golf: - @$(CC) -o $(PROG) $(PROG).c - @./$(PROG) - @chmod +x $(PROG).bin - - @rm $(PROG) $(PROG).bin - -(This is the Makefile you'll find in the repo [0]) - -+-----------------------------------+ -|--[ Falling At The First Hurdle ]--| -+-----------------------------------+ - -As many will already know, file parsers are awful things. While specifications usually have earnest -goals, they are rarely respected by those who should supposedly know better. Chief among such -blasphemers is the Linux ELF loader itself. LibGolf makes it easy to investigate the extent of these -crimes against elf.h. - -A good place to begin is the beginning, which means the ELF header. At the start of any ELF file is -ofcourse, the familar 0x7f followed by ELF, known to its friends as EI_MAG0 through EI_MAG3. -Unsurprisingly, modifying any of these four bytes results in the Linux loader rejecting the file. -Thank goodness for that! - -What about byte 0x5? Our trusty specification tells us that this is the EI_CLASS byte and denotes -the target architecture. Acceptable values are 0x01 and 0x02, for 32- and 64-bit respectively. I'll -say again: acceptable values are 0x01 and 0x02. What if we set it to 0x58 (or "X" for ASCII- -adherents)? We can do that by adding: - - (ehdr->e_ident)[EI_CLASS] = 0x58; - -to our generating C file. (Why 0x58? It shows up clearly in xxd/hexyl output!) - -Once we've got our .bin to play with, before trying to execute it, let's try a couple of other -familar ELF parsing tools in the search for further culprits. First on the list is gdb. Go on, -I'll wait. See what happens? - - "not in executable format: file format not recognized" - -Likewise, objdump will give you a similar answer. It seems these parsers are doing their job -properly. Now, let's try to run the binary normally. - - It works perfectly. - -If you're using my example shellcode, then a consultation with $? will regretably inform you that -the binary exited successfully. The same crimes are commited when setting EI_DATA and EI_VERSION to -illegal values too. - -+---------------------------------------+ -|--[ Turning The Corruption Up To 11 ]--| -+---------------------------------------+ - -So, how far can we go? Just how much of the ELF and program headers will the Linux loader ignore? -We've already covered EI_CLASS, EI_DATA and EI_VERSION, but it turns out that EI_OSABI is also -safely ignored. That takes us up to offset 0x8. According to the spec, next up is EI_ABIVERSION and -EI_PAD which, together, take us all the way to byte 0xf. No one cares about them it seems, so we -can set all of them to 0x58 without fear. - -Marching ever further, we come across a field that appears to be resistant to being messed with: -e_type. Understandably, the Linux loader doesn't like it if we don't tell it what kind of ELF file -we're providing it with (it's nice to know that it does have *some* standards! - pun intended). We -need these two bytes to remain 0x0002 (or ET_EXEC to elf.h acolytes). Next up is another picky byte, -at the all-too-familiar 0x12 offset: e_machine, which designates the target ISA. As far as we're -concerned, by specifying X86_64 as the first argument to INIT_ELF(), this byte has already been -populated with 0x3e for us by LibGolf. - -Suddenly, a wild e_version appeared! We're faced with another dissident, which supposedly should -always be the bytes 0x00000001. However, in practice, no one seems to be interested, so let's fill -it with 0x58585858 instead. - -Following this string of heretics, we have a couple of important fields that appear to be resistant -to abuse; e_entry and e_phoff. I'm sure I needn't go into too much detail about e_entry; it's the -entry point of the binary, where execution is ultimately handed off to once the loadable sections -are in memory. While one might expect that the loader could manage without knowing what the offset -to the program header is, it appears that it isn't smart enough to figure it out without being -spoon-fed. Better leave these two alone. - -LibGolf is yet to support section headers (and given its focus on producing *small* binaries, it is -probably unlikely to support them in the future). This means that, faced with any headers relating -to them, we can fiddle to our heart's content. That includes e_shoff, e_shentsize, eh_shnum and even -e_shstrndx. If we don't have any section headers, we can't be held accountable for corrupting them! - -The remaining fields that are seemingly of some import to the Linux loader are e_ehsize, e_phentsize, -and e_phnum. Again, this isn't too surprising, seeing as they are concerned with loading the only -loadabale segment into memory before handing over control. If you need a refresher, e_ehsize is the -size of the ELF header (which is either 0x34 or 0x40 for 32- and 64-bit respectively), eh_phentsize -is the size of the upcoming program header (again, hardcoded to either 0x20 or 0x38 for 32- and -64-bit architectures). If the loader had been a little more picky about EI_CLASS, it wouldn't need -these two fields. Lastly, e_phnum is just the number of entries in the program header - for us it is -always 0x1. No doubt, this is used for some loop in the memory loading routines, but I haven't -investigated any further yet. - -There is still one field left in the ELF header I haven't touched on, which is e_flags. The reason -is fairly simple, in that it's architecture dependent. For x86_64, it doesn't matter at all because -it's undefined (although it *is* important for some ARM platforms! Take a look at the arm32 example -at [0]). - -That brings us to the end of the ELF header. For those not keeping count, just over 50% of the ELF -header is ignored by the loader. But what about the program header? It turns out that program headers -have a lot less wiggle room in them, but not for the reason one might expect. Indeed, *any* corruption -of the program header will not actually affect the Linux loader. We could fill the whole thing with -our trusty 0x58, and the loader won't care a jot. But beware, bold adventurer, fiddle with the wrong -byte and you'll be plunged into the dungeon of faulty segmentation! - -So, is there anything at all susceptible to coercion in the program header? It transpires that there -are two fields that, by no fault of their own, simply aren't relevant anymore: p_paddr and p_align. -The former was important back in the heady days before virtual memory, where 4GB of RAM was nothing -more than a child's daydream and it was therefore important to inform the loader where in physical -memory the segment should be loaded. - -Memory alignment is a funny one. Supposedly, p_vaddr is meant to equal p_offset modulo p_align. -"Proper" ELF files (at least those compiled with GCC) appear to just set p_offset equal to p_vaddr -and move on. This is also what LibGolf does by default and renders p_align totally superfluous! - -All in all, not as fun as the ELF header, but still some small gains. The binary generating C file -now looks like this: - - #include "libgolf.h" - #include "shellcode.h" - - int main(int argc, char **argv) - { - INIT_ELF(X86_64,64); - - /* - * Breaks common static analysis tools like gdb and objdump - */ - (ehdr->e_ident)[EI_CLASS] = 0x58; // Architecture - (ehdr->e_ident)[EI_DATA] = 0x58; // Endianness - (ehdr->e_ident)[EI_VERSION] = 0x58; // Supposedly, always 0x01 - (ehdr->e_ident)[EI_OSABI] = 0x58; // Target OS - - // Loop over the rest of e_ident - int i; - for ( i = 0 ; i < 0x10 ; i++ ) - (ehdr->e_ident)[i] = 0x58; - - ehdr->e_version = 0x58585858; // Supposedly, always 0x00000001 - - // Section headers? We don't need no stinkin' section headers! - ehdr->e_shoff = 0x5858585858585858; - ehdr->e_shentsize = 0x5858; - ehdr->e_shnum = 0x5858; - ehdr->e_shstrndx = 0x5858; - - ehdr->e_flags = 0x58585858; // x86_64 has no defined flags - - phdr->p_paddr = 0x5858585858585858; // Physical address is ignored - phdr->p_align = 0x5858585858585858; // p_vaddr = p_offset, so irrevelant - - GEN_ELF(); - return 0; - } - -If you compile and run this program, you'll get the following binary: - - 00000000: 7f45 4c46 5858 5858 5858 5858 5858 5858 .ELFXXXXXXXXXXXX - 00000010: 0200 3e00 5858 5858 7800 4000 0000 0000 ..>.XXXXx.@..... - 00000020: 4000 0000 0000 0000 5858 5858 5858 5858 @.......XXXXXXXX - 00000030: 5858 5858 4000 3800 0100 5858 5858 5858 XXXX@.8...XXXXXX - 00000040: 0100 0000 0500 0000 0000 0000 0000 0000 ................ - 00000050: 0000 4000 0000 0000 5858 5858 5858 5858 ..@.....XXXXXXXX - 00000060: 0700 0000 0000 0000 0700 0000 0000 0000 ................ - 00000070: 5858 5858 5858 5858 b03c 4831 ff0f 05 XXXXXXXX. Date: Thu, 27 Apr 2023 15:41:51 +0300 Subject: [PATCH 2/4] Added missed file 1.txt.1 --- 1/txt/1.txt..txt | 324 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 324 insertions(+) create mode 100644 1/txt/1.txt..txt diff --git a/1/txt/1.txt..txt b/1/txt/1.txt..txt new file mode 100644 index 0000000..c899064 --- /dev/null +++ b/1/txt/1.txt..txt @@ -0,0 +1,324 @@ + _ .-') _ ('-. ('-. _ .-') _ .-. .-') .-') _ ('-. .-') +( ( OO) ) _( OO) ( OO ).-.( ( OO) ) \ ( OO ) ( OO) ) _( OO) ( OO ). + \ .'_ (,------./ . --. / \ .'_ ;-----.\ ,--. ,--./ '._(,------.(_)---\_) + ,`'--..._) | .---'| \-. \ ,`'--..._) | .-. | \ `.' / |'--...__)| .---'/ _ | + | | \ ' | | .-'-' | | | | \ ' | '-' /_).-') / '--. .--'| | \ :` `. + | | ' |(| '--.\| |_.' | | | ' | | .-. `.(OO \ / | | (| '--. '..`''.) + | | / : | .--' | .-. | | | / : | | \ || / /\_ | | | .--' .-._) \ + | '--' / | `---.| | | | | '--' / | '--' /`-./ /.__) | | | `---.\ / + `-------' `------'`--' `--' `-------' `------' `--' `--' `------' `-----' + ~ xcellerator + +Ahoy, fellow ELF devotees! In this article, I want to introduce a small library I've been working +on called LibGolf. It started out as simply a vehicle for better understanding the ELF and program +headers, but has since spun into something reasonably practical. It makes is very easy to generate +a binary consisting of an ELF header, followed by a single program header, followed by a single +loadable segment. By default, all the fields in the headers are set to sane values, but there's a +simple way to play with these defaults - and that's what this article is all about! I'm going to +demonstrate how I used LibGolf to enumerate precisely which bytes are necessary and which are +ignored by the Linux loader. Fortunately, it turns out that the loader is one of the least picky +parsers among the standard Linux toolkit. Before we're through, we'll see several popular static +analysis tools crumble before our corrupted ELF, while the loader continues to merrily load and +jump to our chosen bytes. + ++---------------------------+ +|--[ Introducing LibGolf ]--| ++---------------------------+ + +A while back, I'd been playing with writing ELFs by hand in NASM. While this was fun for a while +(and certainly has it's benefits), I realised that I was missing out on all the fun that C structs +have to offer. In particular, as I'm sure many readers will no doubt be aware, , is +packed full of fun things like `Elf64_Ehdr` and `Elf32_Phdr` ripe for declaring. + +Not wanting such helpful headers to go to waste, I elected to take them, and put them to good use. +From these efforts, came libgolf.h, a libary that makes it easy to throw shellcode into a +functioning executable. I know what you're thinking - "this just sounds like a terrible linker!", +and you might be right. However, what's nice here is that you can easily modify the headers *before* +the binary is built. + +Let's take a look at how this works. If you want to play along at home, you can find the source code +for all of this at [0]. You can find the code in this article under 'examples/01_dead_bytes'. The +basic setup needs two files; a C source file and a shellcode.h. As far as shellcode goes, I like to +go with the old faithful 'b0 3c 48 31 ff 0f 05', which disassembles to: + + mov al, 0x3c @ b0 3c + xor rdi, rdi @ 48 31 ff + syscall @ 0f 05 + +(Yes - calling this "shellcode" is pushing things a bit!) + +Essentially, it just calls exit(0). This is nice because we can easily check that these bytes +successfully executed with the shell expansion $?. + +Throw this or some other shellcode (but make sure it's PIC - there's no support for relocatable +symbols yet!) into a buffer called buf[] in shellcode.h and jump back to the C file. If you just +wanted to get a binary that executes your shellcode, then this is all you need: + + #include "libgolf.h" + #include "shellcode.h" + + int main(int argc, char **argv) + { + INIT_ELF(X86_64,64); + + GEN_ELF(); + return 0; + } + +Compiling this and running the resulting executable will provide you with a .bin file - this is +your shiny new ELF! Pretty simple, right? Simplicity is often accompanied by the dull, as is the +case here, so let's do something more interesting! + +Before going on, it's worth explaining what these two macros are doing behind the scenes. First off, +INIT_ELF() takes two arguments, the ISA and the architecture. Currently, LibGolf supports X86_64, +ARM32, and AARCH64 as valid ISAs and either 32 or 64 for the architecture. It first sets up some +internal bookkeeping structs, and decides whether to use the Elf32_* or Elf64_* objects for the +headers. It also automatically assigns pointers to the ELF and program headers, called ehdr and +phdr respectively. It is these that we will use to easily modify the fields. Aside from that, it +also copies the shellcode buffer over, and populates the ELF and program headers before calculating +a sane entry point. Now comes GEN_ELF(), which just prints some nice stats to stdout and then writes +the appropriate structs to the .bin file. The name of the .bin is determined by argv[0]. + +So, after we've used the INIT_ELF() macro, we have ehdr and phdr available to dereference. Suppose +we wanted to modify the e_version field of the ELF header. All we need to do is add a single line: + + #include "libgolf.h" + #include "shellcode.h" + + int main(int argc, char **argv) + { + INIT_ELF(X86_64); + + // Set e_version to 12345678 + ehdr->e_version = 0x78563412; + + GEN_ELF(); + return 0; + } + +Another quick compile and execute, and you'll have another .bin file waiting for you. Taking a look +at this file in xxd, hexyl, or your favourite bin-manipulator of choice, you'll see a pretty little +'12 34 56 78' peeking back at you starting at offset 0x14. Wasn't that easy? + +To make things move a little faster, I like to use the following Makefile: + + .PHONY golf clean + + CC=gcc + CFLAGS=-I. + PROG=golf + + golf: + @$(CC) -o $(PROG) $(PROG).c + @./$(PROG) + @chmod +x $(PROG).bin + + @rm $(PROG) $(PROG).bin + +(This is the Makefile you'll find in the repo [0]) + ++-----------------------------------+ +|--[ Falling At The First Hurdle ]--| ++-----------------------------------+ + +As many will already know, file parsers are awful things. While specifications usually have earnest +goals, they are rarely respected by those who should supposedly know better. Chief among such +blasphemers is the Linux ELF loader itself. LibGolf makes it easy to investigate the extent of these +crimes against elf.h. + +A good place to begin is the beginning, which means the ELF header. At the start of any ELF file is +ofcourse, the familar 0x7f followed by ELF, known to its friends as EI_MAG0 through EI_MAG3. +Unsurprisingly, modifying any of these four bytes results in the Linux loader rejecting the file. +Thank goodness for that! + +What about byte 0x5? Our trusty specification tells us that this is the EI_CLASS byte and denotes +the target architecture. Acceptable values are 0x01 and 0x02, for 32- and 64-bit respectively. I'll +say again: acceptable values are 0x01 and 0x02. What if we set it to 0x58 (or "X" for ASCII- +adherents)? We can do that by adding: + + (ehdr->e_ident)[EI_CLASS] = 0x58; + +to our generating C file. (Why 0x58? It shows up clearly in xxd/hexyl output!) + +Once we've got our .bin to play with, before trying to execute it, let's try a couple of other +familar ELF parsing tools in the search for further culprits. First on the list is gdb. Go on, +I'll wait. See what happens? + + "not in executable format: file format not recognized" + +Likewise, objdump will give you a similar answer. It seems these parsers are doing their job +properly. Now, let's try to run the binary normally. + + It works perfectly. + +If you're using my example shellcode, then a consultation with $? will regretably inform you that +the binary exited successfully. The same crimes are commited when setting EI_DATA and EI_VERSION to +illegal values too. + ++---------------------------------------+ +|--[ Turning The Corruption Up To 11 ]--| ++---------------------------------------+ + +So, how far can we go? Just how much of the ELF and program headers will the Linux loader ignore? +We've already covered EI_CLASS, EI_DATA and EI_VERSION, but it turns out that EI_OSABI is also +safely ignored. That takes us up to offset 0x8. According to the spec, next up is EI_ABIVERSION and +EI_PAD which, together, take us all the way to byte 0xf. No one cares about them it seems, so we +can set all of them to 0x58 without fear. + +Marching ever further, we come across a field that appears to be resistant to being messed with: +e_type. Understandably, the Linux loader doesn't like it if we don't tell it what kind of ELF file +we're providing it with (it's nice to know that it does have *some* standards! - pun intended). We +need these two bytes to remain 0x0002 (or ET_EXEC to elf.h acolytes). Next up is another picky byte, +at the all-too-familiar 0x12 offset: e_machine, which designates the target ISA. As far as we're +concerned, by specifying X86_64 as the first argument to INIT_ELF(), this byte has already been +populated with 0x3e for us by LibGolf. + +Suddenly, a wild e_version appeared! We're faced with another dissident, which supposedly should +always be the bytes 0x00000001. However, in practice, no one seems to be interested, so let's fill +it with 0x58585858 instead. + +Following this string of heretics, we have a couple of important fields that appear to be resistant +to abuse; e_entry and e_phoff. I'm sure I needn't go into too much detail about e_entry; it's the +entry point of the binary, where execution is ultimately handed off to once the loadable sections +are in memory. While one might expect that the loader could manage without knowing what the offset +to the program header is, it appears that it isn't smart enough to figure it out without being +spoon-fed. Better leave these two alone. + +LibGolf is yet to support section headers (and given its focus on producing *small* binaries, it is +probably unlikely to support them in the future). This means that, faced with any headers relating +to them, we can fiddle to our heart's content. That includes e_shoff, e_shentsize, eh_shnum and even +e_shstrndx. If we don't have any section headers, we can't be held accountable for corrupting them! + +The remaining fields that are seemingly of some import to the Linux loader are e_ehsize, e_phentsize, +and e_phnum. Again, this isn't too surprising, seeing as they are concerned with loading the only +loadabale segment into memory before handing over control. If you need a refresher, e_ehsize is the +size of the ELF header (which is either 0x34 or 0x40 for 32- and 64-bit respectively), eh_phentsize +is the size of the upcoming program header (again, hardcoded to either 0x20 or 0x38 for 32- and +64-bit architectures). If the loader had been a little more picky about EI_CLASS, it wouldn't need +these two fields. Lastly, e_phnum is just the number of entries in the program header - for us it is +always 0x1. No doubt, this is used for some loop in the memory loading routines, but I haven't +investigated any further yet. + +There is still one field left in the ELF header I haven't touched on, which is e_flags. The reason +is fairly simple, in that it's architecture dependent. For x86_64, it doesn't matter at all because +it's undefined (although it *is* important for some ARM platforms! Take a look at the arm32 example +at [0]). + +That brings us to the end of the ELF header. For those not keeping count, just over 50% of the ELF +header is ignored by the loader. But what about the program header? It turns out that program headers +have a lot less wiggle room in them, but not for the reason one might expect. Indeed, *any* corruption +of the program header will not actually affect the Linux loader. We could fill the whole thing with +our trusty 0x58, and the loader won't care a jot. But beware, bold adventurer, fiddle with the wrong +byte and you'll be plunged into the dungeon of faulty segmentation! + +So, is there anything at all susceptible to coercion in the program header? It transpires that there +are two fields that, by no fault of their own, simply aren't relevant anymore: p_paddr and p_align. +The former was important back in the heady days before virtual memory, where 4GB of RAM was nothing +more than a child's daydream and it was therefore important to inform the loader where in physical +memory the segment should be loaded. + +Memory alignment is a funny one. Supposedly, p_vaddr is meant to equal p_offset modulo p_align. +"Proper" ELF files (at least those compiled with GCC) appear to just set p_offset equal to p_vaddr +and move on. This is also what LibGolf does by default and renders p_align totally superfluous! + +All in all, not as fun as the ELF header, but still some small gains. The binary generating C file +now looks like this: + + #include "libgolf.h" + #include "shellcode.h" + + int main(int argc, char **argv) + { + INIT_ELF(X86_64,64); + + /* + * Breaks common static analysis tools like gdb and objdump + */ + (ehdr->e_ident)[EI_CLASS] = 0x58; // Architecture + (ehdr->e_ident)[EI_DATA] = 0x58; // Endianness + (ehdr->e_ident)[EI_VERSION] = 0x58; // Supposedly, always 0x01 + (ehdr->e_ident)[EI_OSABI] = 0x58; // Target OS + + // Loop over the rest of e_ident + int i; + for ( i = 0 ; i < 0x10 ; i++ ) + (ehdr->e_ident)[i] = 0x58; + + ehdr->e_version = 0x58585858; // Supposedly, always 0x00000001 + + // Section headers? We don't need no stinkin' section headers! + ehdr->e_shoff = 0x5858585858585858; + ehdr->e_shentsize = 0x5858; + ehdr->e_shnum = 0x5858; + ehdr->e_shstrndx = 0x5858; + + ehdr->e_flags = 0x58585858; // x86_64 has no defined flags + + phdr->p_paddr = 0x5858585858585858; // Physical address is ignored + phdr->p_align = 0x5858585858585858; // p_vaddr = p_offset, so irrevelant + + GEN_ELF(); + return 0; + } + +If you compile and run this program, you'll get the following binary: + + 00000000: 7f45 4c46 5858 5858 5858 5858 5858 5858 .ELFXXXXXXXXXXXX + 00000010: 0200 3e00 5858 5858 7800 4000 0000 0000 ..>.XXXXx.@..... + 00000020: 4000 0000 0000 0000 5858 5858 5858 5858 @.......XXXXXXXX + 00000030: 5858 5858 4000 3800 0100 5858 5858 5858 XXXX@.8...XXXXXX + 00000040: 0100 0000 0500 0000 0000 0000 0000 0000 ................ + 00000050: 0000 4000 0000 0000 5858 5858 5858 5858 ..@.....XXXXXXXX + 00000060: 0700 0000 0000 0000 0700 0000 0000 0000 ................ + 00000070: 5858 5858 5858 5858 b03c 4831 ff0f 05 XXXXXXXX. Date: Fri, 28 Apr 2023 12:52:23 +0300 Subject: [PATCH 3/4] Fixed some shitty file name --- 1/txt/{1.txt..txt => 1.txt.} | 1 + 1 file changed, 1 insertion(+) rename 1/txt/{1.txt..txt => 1.txt.} (99%) diff --git a/1/txt/1.txt..txt b/1/txt/1.txt. similarity index 99% rename from 1/txt/1.txt..txt rename to 1/txt/1.txt. index c899064..c5b8f80 100644 --- a/1/txt/1.txt..txt +++ b/1/txt/1.txt. @@ -322,3 +322,4 @@ A special "ahoy" to everyone at Thugcrowd, Symbolcrash, and the Mental ELF Suppo [0] https://www.github.com/xcellerator/libgolf [1] https://n0.lol/ebm/1.html + From 8dcdc4e17714728f57e939d3e9f1bff7b1d0379f Mon Sep 17 00:00:00 2001 From: krispy Date: Fri, 28 Apr 2023 12:55:45 +0300 Subject: [PATCH 4/4] Removed unnecessary newline --- 1/txt/1.txt. | 1 - 1 file changed, 1 deletion(-) diff --git a/1/txt/1.txt. b/1/txt/1.txt. index c5b8f80..c899064 100644 --- a/1/txt/1.txt. +++ b/1/txt/1.txt. @@ -322,4 +322,3 @@ A special "ahoy" to everyone at Thugcrowd, Symbolcrash, and the Mental ELF Suppo [0] https://www.github.com/xcellerator/libgolf [1] https://n0.lol/ebm/1.html -