Shellcode: คำสั่งที่ผิดกฎหมาย
ฉันเป็นคนใหม่ในการพัฒนาเชลล์โค้ดและฉันไม่เข้าใจว่าทำไมเชลล์โค้ดที่สร้างขึ้นจึงไม่ทำงานตามที่คาดไว้
รหัสแอสเซมเบลอร์:
จากคำตอบสำหรับคำถามก่อนหน้าของฉัน
.section .data
cmd: .string "/bin/sh" /* command string */
hand: .string "-c" /* command arguments string */
args: .string "ls -al" /* arguments string */
argv: .quad cmd /* array of command, command arguments and arguments */
.quad hand
.quad args
.quad 0
.section .text
.globl _start
_start:
movq $59, %rax /* call execve system call */ leaq cmd(%rip), %rdi /* save command to rdi */ leaq argv(%rip), %rsi /* save args to rsi */ movq $0, %rdx /* save NULL to rdx */
syscall /* make system call */
รหัสทดสอบ C:
#include<stdio.h>
#include<string.h>
unsigned char shellcode[] = "\x48\xc7\xc0\x3b\x00\x00\x00\x48\x8d\x3d\xf2\x0f\x00\x00\x48\x8d\x35\xfd\x0f\x00\x00\x48\xc7\xc2\x00\x00\x00\x00\x0f\x05";
int main()
{
int (*ret)() = (int(*)())shellcode;
ret();
}
เอาท์พุต:
Illegal instruction
รายละเอียด: Kali Linux GNU / Linux i386 x86_64
คำตอบ
ปัญหาเกี่ยวกับโค้ดของคุณคือสตริงเชลล์ที่คุณสร้างขึ้นไม่มีข้อมูลใด ๆ และข้อมูลมีตัวชี้ค่าสัมบูรณ์ดังนั้นตำแหน่งจะไม่เป็นอิสระดังนั้นจะไม่ได้ผลหากคุณย้ายไป.textและรวมไว้ เมื่อรันภายในโปรแกรมอื่นตามที่คุณทำในรหัสCโปรแกรมจะพยายามค้นหาข้อมูลที่ไม่มีอยู่และในตำแหน่งหน่วยความจำคงที่ซึ่งไม่ได้ใช้กับโปรแกรมที่ใช้ประโยชน์ได้ที่คุณกำลังเรียกใช้อยู่ภายใน
ฉันคิดว่าคุณอาจมีปัญหาอื่นที่ก่อให้เกิดการเรียนการสอนที่ผิดกฎหมาย คุณไม่ได้แสดงให้เห็นว่าคุณสร้างโปรแกรมCของคุณอย่างไร แต่ฉันสงสัยว่ามันเป็น 32 บิตและเชลล์โค้ดของคุณเป็น 64 บิตหรือไม่ ฉันเริ่มคิดว่าโปรแกรมCของคุณอาจถูกคอมไพล์เป็นโปรแกรม 32 บิตและคำสั่งที่ผิดกฎหมายอาจเป็นเพราะคุณไม่สามารถรันโค้ด 64 บิต (เชลล์โค้ด) ในโปรแกรม 32 บิตได้อย่างน่าเชื่อถือ ตัวอย่างเช่นSYSCALLคำสั่งคือ opcode ที่ไม่ถูกต้องในโปรแกรม 32 บิตบน CPU ที่ไม่ใช่ AMD นี่เป็นเพียงการคาดเดาในกรณีที่ไม่มีรายละเอียดเพิ่มเติมเกี่ยวกับวิธีที่คุณรวบรวม / ประกอบ / เชื่อมโยงรหัสเชลล์และโปรแกรมCของคุณ
คุณจะต้องสร้างรหัสอิสระตำแหน่ง (PIC) เพื่อให้สามารถทำงานได้ทุกที่เมื่อโหลดบนสแต็ก ข้อมูลของคุณจะต้องวางไว้ในกลุ่มด้วยรหัส โค้ดยังต้องหลีกเลี่ยงการสร้างอักขระ NUL (0x00) เนื่องจากจะยุติสตริงก่อนกำหนดหากระบุไว้เป็นอินพุตของผู้ใช้ไปยังโปรแกรมที่ใช้ประโยชน์ได้จริง
เวอร์ชันของรหัสของคุณที่สามารถใช้เพื่อวัตถุประสงค์ดังกล่าวอาจมีลักษณะดังนี้:
shellcode.s :
# This shell code is designed to avoid any NUL(0x00) byte characters being generated
# and is coded to be position independent.
.section .text
.globl _start
_start:
jmp overdata # Mix code and DATA in same segment
# Generate all the strings without a NUL(0) byte. We will replace the 0xff
# with 0x00 in the code
name:.ascii "/bin/sh" # Program to run
name_nul: .byte 0xff # This 0xff will be replaced by 0x00 in the code
arg1:.ascii "-c" # Program argument
arg1_nul: .byte 0xff # This 0xff will be replaced by 0x00 in the code
arg2:.ascii "ls" # Program Argument
arg2_nul: .byte 0xff # This 0xff will be replaced by 0x00 in the code
overdata:
xor %eax, %eax # RAX = 0
# All references to the data before our code will use a negative offset from RIP
# and use a 4 byte displacement. This avoids producing unwanted NUL(0) characters
# in the code. We use RIP relative addressing so the code will be position
# independent once loaded in memory.
# Zero terminate each of the strings
mov %al, arg2_nul(%rip)
mov %al, arg1_nul(%rip)
mov %al, name_nul(%rip)
lea name(%rip), %rdi # RDI = pointer to program name string
push %rax # NULL terminate the program argument array
leaq arg2(%rip), %rsi
push %rsi # Push address of the 3rd program argument on stack
lea arg1(%rip), %rsi
push %rsi # Push address of the 2nd program argument on stack
push %rdi # Push address of the program name on stack as 1st arg
mov %rsp, %rsi # RSI = Pointer to the program argument array
mov %rax, %rdx # RDX = 0 = NULL envp parameter
mov $59, %al # RAX = execve system call number
syscall
คุณสามารถสร้างสตริงสไตล์ C ด้วย:
as --64 shellcode.s -o shellcode.o
ld shellcode.o -o shellcode
objcopy -j.text -O binary shellcode shellcode.bin
hexdump -v -e '"\\""x" 1/1 "%02x" ""' shellcode.bin
hexdumpคำสั่งดังกล่าวเอาท์พุทจะ:
\ xeb \ x0e \ x2f \ x62 \ x69 \ x6e \ x2f \ x73 \ x68 \ xff \ x2d \ x63 \ xff \ x6c \ x73 \ xff \ x31 \ xc0 \ x88 \ x05 \ xf7 \ xff \ xff \ xff \ x88 \ x05 \ xee \ xff \ xff \ xff \ x88 \ x05 \ xe5 \ xff \ xff \ xff \ x48 \ x8d \ x3d \ xd7 \ xff \ xff \ xff \ x50 \ x48 \ x8d \ x35 \ xda \ xff \ xff \ xff \ x56 \ x48 \ x8d \ x35 \ xcf \ xff \ xff \ xff \ x56 \ x57 \ x48 \ x89 \ xe6 \ x48 \ x89 \ xc2 \ xb0 \ x3b \ x0f \ x05
คุณจะสังเกตเห็นว่าไม่มี\x00อักขระใดที่แตกต่างจากรหัสของคุณ คุณสามารถใช้สตริงนี้โดยตรงในโปรแกรมCเช่น:
Exploit.c :
int main(void)
{
char shellcode[]="\xeb\x0e\x2f\x62\x69\x6e\x2f\x73\x68\xff\x2d\x63\xff\x6c\x73\xff\x31\xc0\x88\x05\xf7\xff\xff\xff\x88\x05\xee\xff\xff\xff\x88\x05\xe5\xff\xff\xff\x48\x8d\x3d\xd7\xff\xff\xff\x50\x48\x8d\x35\xda\xff\xff\xff\x56\x48\x8d\x35\xcf\xff\xff\xff\x56\x57\x48\x89\xe6\x48\x89\xc2\xb0\x3b\x0f\x05";
int (*ret)() = (int(*)())shellcode;
ret();
return 0;
}
สิ่งนี้จะต้องถูกคอมไพล์และเชื่อมโยงกับสแต็กที่เรียกใช้งานได้:
gcc -zexecstack exploit.c -o exploit
strace ./exploitจะสร้างการEXECVEเรียกระบบคล้ายกับ:
execve ("/ bin / sh", ["/ bin / sh", "-c", "ls"], NULL) = 0
หมายเหตุ : ฉันจะสร้างสตริงเป็นการส่วนตัวโดยใช้โปรแกรมบนสแต็กคล้ายกับโค้ดในคำตอบ Stackoverflowอื่นที่ฉันเขียน