Didier Stevens

Thursday 27 August 2009

The Brucon WiFi Puzzle Solution

Filed under: Puzzle — Didier Stevens @ 14:16

Here’s one way to solve the Brucon WiFi Puzzle: open the capture file with Wireshark.

The capture file contains one beacon frame for the brucon09wifi network. If you’re a bit familiar with beacon frames, one tag will stand out: the vendor specific tag which Wireshark can’t interpret because it’s from a vendor it doesn’t know.

bruconwifipuzzle-1

The hidden data is inside the vendor specific tag. Select it and export the selected bytes:

bruconwifipuzzle-2b

How do you decode this data? You can try all types of encoding and encryption schemes, but to prevent you from wasting time trying countless possibilities, I’ve given you a hint in the name of the vendor: XortecOy. The data is XOR-encrypted. And the key is tecOy. 😉

Open the saved bytes with Cryptool:

bruconwifipuzzle-3

And apply XOR-decryption with key tecOy:

bruconwifipuzzle-4

Et voilà!

Wednesday 26 August 2009

Yubikey, Trojans and Twitter

Filed under: Encryption,Hardware,Malware — Didier Stevens @ 11:33

Stina, Yubico’s CEO, gave me a Yubikey at RSA London last year. It’s a small keyfob simulating a USB keyboard. Each time you press the button while it’s inserted in a USB port, it generates a one-time-password.

20090825-221451

The Yubikey is a clever little two-factor authentication device.

But I’ve some issues using the Yubikey in a really secure system. As Twitter plays a role in this, and because lately Twitter started to be used by trojans as a communication channel, I decided it’s time to publish the issues I encountered together with mitigating actions.

Technical details

The OTP generated by the Yubikey is an AES-encrypted data stream. I’ve obtained the AES-key embedded in my Yubikey from Yubico and am able to decode the OTP with a simple Python program.

Insert Yubikey and start generating OTPs:

OTP: lkeuuuceeeivjgtbjcbevigeccerfufugdijuhflckrd
public_id = lkeuuuceeeiv
secret_id = ************
counter = 26
counter_session = 1
random_number = 13042
timestamp = 0x8321a8
  • public_id and secret_id identifies the Yubikey (notice that the public_id is the prefix of the OTP).
  • counter: this is a persistent register. It is increased with 1 each time the Yubikey is inserted in a USB port.
  • counter_session: this is a volatile register. It is set to 0 each time the Yubikey is inserted in a USB port, and increased with 1 for each OTP generation
  • random_number is what it says on the tin: a random number, different per OTP
  • timestamp is a volatile 32-bit register. It is set to a random value each time the Yubikey is inserted in a USB port, and is then increased with 1 by a 8Hz clock. Yubico specifies an average variation of 20% on the 8Hz clock per Yubikey. With the measurements I made, I calculate that the 8Hz clock of my key has a 32% deviation.

Validating an OTP is done by successfully decrypting the OTP. Replay attacks are mitigated by comparing the counters and timestamp with historical data.

When trying to design a website that uses the Yubikey to authenticate, I imagined the following attack and found a way to mitigate it.

Attack 1:

Assume a website that uses the Yubikey to logon (i.e. an OTP generated with your Yubikey is needed to log on to the site, possibly together with more classic credentials like a username/password combo).
Because this website has my AES key and can decrypt my OTP, my Yubikey authenticates me and I’m granted access to the site.
A web browser trojan could steal an OTP like this:

  1. I generate an OTP (OTP1) with my Yubikey
  2. The trojan intercepts and stores OTP1, doesn’t send OTP1 to the website, but makes the browser display a fake error message (404, server load too high, Yubikey error, …) prompting me to generate a second OTP
  3. I’m fooled by the fake error, and generate a second OTP (OTP2) with my Yubikey
  4. The trojan intercepts and stores OTP2, and sends OTP1 to the website
  5. The website grants me access, and the trojan stops interfering
  6. OTP2 can be used by the operators of the trojan to get access to the website, as long as I’m not first to access the website at a later time with a new OTP (OTP3). Twitter could be used as a channel to communicate the OTPs in real-time to the trojan operators.

Mitigation:

The website can detect this attack (the malicious use of OTP2) if the following algorithm is implemented:

  1. for every account, the last valid OTP is stored, together with a server-side timestamp (when it was received by the website)
  2. if a new OTP is received, the counter value of the previous OTP is compared with the counter value of the new OTP
  3. when both counters have the same value, the website knows that the OTPs were generated in the same session, and thus that it can compare timestamps.
  4. it calculates the delta of the timestamps of the OTPs, and also the delta of the server-side timestamps when it received the OTPs.
  5. if the 2 deltas differ too much (more than 20% margin), then it refuses the OTP and doesn’t grand access to the website

But now comes the second attack for which I have no mitigation, despite some help from the Yubico forum.

Attack 2:

Assume a website which uses the Yubikey OTP to 1) authenticate users and 2) validate transactions. A classic example of such a site is an online banking site. The user generates an OTP to logon, and then has to generate an OTP for each financial transaction.
A web browser trojan could insert its own transaction like this:

  1. I generate an OTP (OTP1) with my Yubikey
  2. The trojan intercepts and stores OTP1 together with a timestamp, doesn’t send OTP1 to the website, but makes the browser display a fake error message (404, server load too high, Yubikey error, …) prompting me to generate a second OTP
  3. I’m fooled by the fake error, and generate a second OTP (OTP2) with my Yubikey
  4. The trojan intercepts and stores OTP2 together with a timestamp, and sends OTP1 to the website
  5. The website grants me access
  6. After an amount of time equal to the delta between the 2 stored timestamps, the trojan starts a transaction (invisible to the user) and uses OTP2 to validate the transaction.
  7. When I start my own transactions, the trojan passes the OTPs on to the website, but delays them with the same timestamp delta to avoid post-exploitation detection.

I can’t device an algorithm to detect this fraud server-side, if the Yubikey is the only authentication and validation mechanism used. This attack would not work with a challenge-response token, because the keys generated by such a token are different for logon and transaction validation. Typically, these tokens generate one type of keys for logon, and another type of keys based on a challenge for transactions. The challenge encodes data of the transaction, so that a particular challenge can’t be used for another transaction.

One Yubico forum member suggests a type of CAPTCHA to ensure that each submitted OTP is submitted by a human (hence the CAPTCHA), but I don’t believe this is practical, as malware is able to defeat some CAPTCHAs and humans are unable to solve some CAPTCHAs.

Feel free to post a comment with your migitation suggestions, but please keep them practical ;-).

Sunday 23 August 2009

Quickpost: Ardubot Programming

Filed under: Hardware,Quickpost — Didier Stevens @ 14:15

Here’s a small post with extra details on building an Ardubot; details I didn’t find online.

The missing info is which Arduino output lines control the 2 motors. Measuring with a multimeter reveals digital outputs 3, 5, 6 and 9.

I place and solder the motors like this:

The +-sign closest to the PCB:

ardubot-motor-plus-sign

Red wire soldered to + connector, black wire soldered to – connector:

ardubot-motor-wires

I defined left motor and right motor like this:

ardubot

And here’s the schema:

ardubot-schema

To power the left motor in a forward drive, set digital output 9 high and digital output 6 low.

To power the left motor in a reverse drive, do the oposite of a forward drive (9 low and 6 high).

To power down a motor, set both digital outputs low.

To power the right motor in a forward drive, set digital output 5 low and digital output 3 high.

To power the right motor in a reverse drive, do the oposite of a forward drive (5 high and 3 low).

Arduino code:

/*
	Ardubot motor-driving example program
	Version 0.0.1
	Source code put in public domain by Didier Stevens, no Copyright
	https://DidierStevens.com
	Use at your own risk

	History:
	2009/08/21: Start development
	2009/08/23: refactoring
*/

unsigned char PIN_HBRIDGE_1A = 9;
unsigned char PIN_HBRIDGE_2A = 6;
unsigned char PIN_HBRIDGE_3A = 5;
unsigned char PIN_HBRIDGE_4A = 3;

void MotorLeftStop()
{
  digitalWrite(PIN_HBRIDGE_1A, LOW);
  digitalWrite(PIN_HBRIDGE_2A, LOW);
}

void MotorLeftForward()
{
  digitalWrite(PIN_HBRIDGE_1A, HIGH);
  digitalWrite(PIN_HBRIDGE_2A, LOW);
}

void MotorLeftReverse()
{
  digitalWrite(PIN_HBRIDGE_1A, LOW);
  digitalWrite(PIN_HBRIDGE_2A, HIGH);
}

void MotorRightStop()
{
  digitalWrite(PIN_HBRIDGE_3A, LOW);
  digitalWrite(PIN_HBRIDGE_4A, LOW);
}

void MotorRightForward()
{
  digitalWrite(PIN_HBRIDGE_3A, LOW);
  digitalWrite(PIN_HBRIDGE_4A, HIGH);
}

void MotorRightReverse()
{
  digitalWrite(PIN_HBRIDGE_3A, HIGH);
  digitalWrite(PIN_HBRIDGE_4A, LOW);
}

void setup() {
  pinMode(PIN_HBRIDGE_1A, OUTPUT);
  pinMode(PIN_HBRIDGE_2A, OUTPUT);
  pinMode(PIN_HBRIDGE_3A, OUTPUT);
  pinMode(PIN_HBRIDGE_4A, OUTPUT);
}

void loop(){
  MotorLeftStop();
  MotorRightStop();
  delay(2000);

  MotorLeftForward();
  delay(2000);

  MotorLeftStop();
  delay(2000);

  MotorLeftReverse();
  delay(2000);

  MotorLeftStop();
  delay(2000);

  MotorRightForward();
  delay(2000);

  MotorRightStop();
  delay(2000);

  MotorRightReverse();
  delay(2000);

  MotorRightStop();
  delay(2000);

  delay(5000);
}

One tip: if you use the large wheels, get a header kit to raise the Arduino Duemilanove, otherwise the wheel will block access to the power and USB connectors:

ardubot-header-kit


Quickpost info


Friday 21 August 2009

Update: Time Lapse Photography with a Nokia Mobile

Filed under: My Software,Update — Didier Stevens @ 14:51

I’ve debugged the issues some people had with my Nokia time lapse Python script, you can find a new version here.

Tuesday 11 August 2009

Update: UserAssist Tool Version 2.4.3

Filed under: Forensics,My Software,Update — Didier Stevens @ 16:07

I had an interesting discussion with Hans Heins concerning the timestamp displayed by my UserAssist tool.

The first version of the UserAssist tool would only decode the UserAssist registry keys of the account under which it was running. And thus it made sense to display the timestamp in local time format, even if the entry is stored in UTC.

I added a warning about the time zones when I added registry file import functions, but this was confusing.

This new version of the UserAssist tool adds an extra column, with the timestamp in UTC:

20090811-175725

And I’ll be posting a new version to support the new UserAssist registry key format of Windows 7 and Windows 2008 R2.

Download:

UserAssist_V2_4_3.zip (https)

MD5: A5244C7F83E0DE70600E27F5D3B8AD7D

SHA256: 7E2D107BE84FBBF7E79F1BD11703401A374B5138B2F77E4FF8AFE1A3E749CCDA

Thursday 6 August 2009

Update: pdf-parser Version 0.3.5

Filed under: My Software,PDF,Update — Didier Stevens @ 0:05

After PDFiD, it’s pdf-parser’s turn to get updated.

The major change is support for /Names obfuscation through canonicalization. Now that these obfuscation techniques are found in in-the-wild samples, this feature became a necessity. For example, searching for /JavaScript when the PDF document contains /Java#53cript will also retrieve this obfuscated instance.

And if you need to see the obfuscated names like they are, use option –nocanonicalizedoutput

Support for filter ASCII85Decode has been added.

And option –hash displays the MD5 hash value of objects, making it easier to compare 2 PDF documents.

Download:

pdf-parser_V0_3_5.zip (https)

MD5: 07EA2C47766ADF248102E378C65D03F3

SHA256: 5EAD0F9BE9693EF836CF67FF2B796324ED5E7053D34BF4FA588D250A7DA2E761

Wednesday 5 August 2009

Update: PDFiD Version 0.0.8

Filed under: My Software,PDF,Update — Didier Stevens @ 12:33

PDFiD is updated.

Changes:

  • It detects Flash in PDF (/RichMedia)
  • Actions launched by Forms (/AcroForm)
  • Less stringent %PDF header checking, because I saw some samples designed to bypass pddfid
  • Updated the date format
  • New option –force:  force the scanning of a file, even if no valid %PDF header was found
  • Accepts stdin for pipes, example:  pdf-parser.py –filter –type /ObjStm flash.pdf | pdfid.py –force
    This will scan objects “hidden” in object streams (/objStm)

Download:

pdfid_v0_0_8.zip (https)

MD5: 9769FB96899F3AD15510C903A4FB29EF

SHA256: 542734C2613439851AF99B59725B1607F96A6E9396B447C5BD3AF197AABB0231

Blog at WordPress.com.