Didier Stevens

Thursday 31 March 2022

spring4shell Capture File

Filed under: Networking,Vulnerabilities — Didier Stevens @ 19:13

If you are interested, I’ve put a spring4shell exploit capture file on my GitHub.

It might trigger your AV, like Defender (Defender triggers on the webshell code).

First HTTP request in the capture file, is just a test query.

Second HTTP request is the exploit that drops a webshell.

Third HTTP request is using that webshell.

Figure 1: just a test request
Figure 2: exploit dropping a webshell
Figure 3: using the webshell

Tuesday 8 February 2022

Windows Explorer: Improper Exif Data Removal

Filed under: Forensics,Vulnerabilities,Windows 7 — Didier Stevens @ 20:53

Windows explorer has an option to remove properties from media files: “Remove Properties and Personal Information”. For example, removing Exif data from JPEG files.

There is an issue with this feature: it does not properly remove Exif data.

Within an open folder (Windows explorer), select a media file (I’m using Canon_40D.jpg), right-click and select properties:

Select Details:

Then click “Remove Properties and Personal Information”:

When you click OK, a new file will be created: Canon_40D – Copy.jpg (I renamed this file to Canon_40D-redacted-W11.jpg, because I tested this first on my Windows 11 machine).

File Canon_40D.jpg contains Exif data pertaining to the camera, like its maker and model:

File Canon_40D-redacted-W11.jpg (the redacted version of file Canon_40D.jpg) contains less Exif data: the maker and model properties have been removed:

Looking at the redacted file with binary editor 010 Editor, I noticed that these properties had not been completely removed. Let me explain.

JPEG files are composed of segments of data, these segments can be analyzed with my tool jpegdump.py.

Here is the output for file Canon_40D.jpg (original file), I’m using option -E to include the SHA256 hash of the data of each segment:

And here is the output for file Canon_40D-redacted-W11.jpg (redacted file):

Notice that all the hashes of the segments are identical, except for the third segment, APP1. This segment contains the Exif data. This means that only the Exif data has changed, nothing else, like the picture itself.

Segments APP1 of both pictures have the same size, 2476 bytes. Although properties have been removed, Microsoft Explorer’s removal feature did not shrink the segment.

When I open the original file (Canon_40D.jpg) with 010 Editor, a template for JPEG files is automatically used to parse the structure of the JPEG file. This can be seen in the Template Results below the hexadecimal dump:

The JPG template is also able to parse Exif data: I drilled down in the template hierarchy, until I found the Exif properties (circled in red). There are 11 properties, the first is Make (tag 0x010F) and the second one is Model (tag 0x0110).

Opening the template DIRENTRY structure for property Make reveals the following fields:

Remark that the string “Canon”, that is the string value of the Make property, is not contained inside the DIRENTRY structure for said property. What it does contain, is the size of the string (6 bytes) and an offset to the string itself (an offset of 146 bytes). Literal string values (StrAscii structures) are stored inside the Exif data structure, after the list of DIRENTRY structures.

It is the same for the Model property:

The Model DIRENTRY structure points to an ASCII string (StrAscii), size is 4 bytes and offset is 152 bytes.

Let’s take a look now, again with 010 Editor, at the cleaned file that was created by clicking “Remove Properties and Personal Information” (Canon_40D-redacted-W11.jpg):

Notice that this file has 8 DIRENTRY structures in stead of 11: 3 Exif properties have been removed (Make, Model & Software). And the StrAscii structures for these 3 properties do not appear in the template result.

However, these 3 StrAscii string values are still inside the APP1 segment:

They are at the exact same location as in the original file (Canon_40D.jpg):

Conclusion: when you use Windows Explorer’s “Remove Properties and Personal Information” feature, Exif properties will be removed, but if these are string properties, they are not completely removed.

Windows Explorer’s “Remove Properties and Personal Information” feature removes DIRENTRY structures (properties), but does not remove StrAscii structures (properties’ string values).

When the Exif data of JPEG files cleaned with this feature is viewed, the orphaned strings will not appear. But when they are viewed with a binary editor, these strings do appear. And of course, they can also be easily visualized with a strings utility (here I’m using my strings utility strings.py):

You will not know to which properties these strings belong, because that information has been erased (DIRENTRY structures). But here, just the string values themselves, are enough to know that this is a Canon camera and that GIMP software was used to produce the final picture.

In case you want to test this yourself and try to reproduce my findings, you can download file Canon_40D.jpg from here. The file I created by using Windows Explorer’s “Remove Properties and Personal Information” feature, Canon_40D-redacted-W11.jpg, has a SHA256 of 8B190028D0F9F2A6F7EDB1DC0955008D73173C32C19C32CE62372C7163EE1223. I tested this on a fully patched Windows 10 machine (21H2) and a fully patched Windows 11 machine. The results where completely identical.

And as I know that some remaining Windows 7 users will want to know if Windows 7 is also affected: a fully patched Windows 7 machine has the same issue (though the cleaned file was different from the W10/W11 file).

If you absolutely want to make sure that all metadata is gone from your media files, do not use Windows Explorer (for the moment). Use another tool. Ideally, use a tool that completely removes the segments containing metadata (APP1, APP2, …).

I did inform Microsoft about this issue.

Friday 12 March 2021

Quickpost: “ProxyLogon PoC” Capture File

Filed under: Forensics,Networking,Quickpost,Vulnerabilities — Didier Stevens @ 18:43

I was able to get the “ProxyLogon PoC” Python script running against a vulnerable Exchange server in a VM. It required some tweaks to the code, and also a change in Exchange permissions, as explained in this tweet by @irsdl.

I created a capture file:

More details will follow.

Update: I added a second capture file (proxylogon-poc-capture-with-keys-and-webshell.pcapng), this one includes a request to the webshell that was installed.

proxylogon-poc-capture-with-keys_V2.zip (https)
MD5: A005AC9CCE0F833C99B5113E79005C7D
SHA256: AA092E099141F8A09F62C3529D8B27624CD11FF348738F78CA9A1E657F999755

Quickpost info

Tuesday 18 April 2017


Filed under: maldoc,Malware,Vulnerabilities — Didier Stevens @ 0:00

I have an analysis of a CVE-2017-0199 maldoc with my tools here, and produced 2 videos:

In the second video, I use nixawk‘s Metasploit module for cve-2017-0199 (not yet merged into the Metasploit GitHub repository at time of writing).

Thursday 23 April 2015

MS15-034: PoC Excel Video

Filed under: Hacking,Vulnerabilities — Didier Stevens @ 19:31

Since I like to hack with Excel, I made a PoC for MS15-034 in VBA/Excel.

PS: If you want to see my videos as soon as they are published, subscribe to my video blog videos.DidierStevens.com or YouTube Channel.

Here’s the video:

Friday 17 April 2015

MS15-034 Detection: Some Observations

Filed under: Networking,Vulnerabilities — Didier Stevens @ 9:15

Several detection rules (SNORT, F5, …) are being published these days to detect exploitation of vulnerability MS15-034.

If you are making or modifying such detection rules, I want to share some observations with you.

MS15-034 can be exploited with a GET request with a specially crafted Range header.

Here is the example we’ll use: Range: bytes=2-18446744073709551615

Referring to RFC 2616 section 14.35.1, you can see that this is not the only way to specify a range. Here is the BNF:

ranges-specifier = byte-ranges-specifier
byte-ranges-specifier = bytes-unit “=” byte-range-set
byte-range-set  = 1#( byte-range-spec | suffix-byte-range-spec )
byte-range-spec = first-byte-pos “-” [last-byte-pos]
first-byte-pos  = 1*DIGIT
last-byte-pos   = 1*DIGIT

suffix-byte-range-spec = “-” suffix-length
suffix-length = 1*DIGIT

First of all, whitespace is allowed. So Range: bytes = 2 – 18446744073709551615 is valid (and also caused a BSOD on my test machine).

Second, numbers can have leading zeroes. So Range: bytes=2-018446744073709551615 is valid (and also caused a BSOD on my test machine).

Third, multiple ranges are allowed. So Range: bytes=2-3,4-18446744073709551615 is valid (this did not cause a BSOD on my test machine).

If you are using rules that don’t detect these cases properly, then attackers can easily evade detection. One space character could be all it takes to evade detection. If the rule looks for string “-18446744073709551615”, then using string “- 18446744073709551615” in the attack (extra space character added) will evade detection.

Thursday 24 April 2014

ssl-hearbleed.nse mod

Filed under: Networking,Vulnerabilities — Didier Stevens @ 7:36

YAHP: Yet Another Heartbleed Post

Update: Daniel Miller told me this modification is not necessary. You can force a script to run on all open ports, regardless of the result of the portrule function, by prefixing the scriptname with a +. Like this: nmap -p443 –script +ssl-heartbleed cloudflarechallenge.com


I’ve read that some people are surprised by Nmap’s ssl-heartbleed.nse script behavior: that it will not test all ports.

The script is designed to test only ports with ssl. This is encoded in the portrule function:

portrule = function(host, port)
  return shortport.ssl(host, port) or sslcert.isPortSupported(port)

It’s explained here that you should do a service version detection scan (-sV) so that the script will test unusual ports.

If you don’t want to do a service version detection scan, you could change the portrule function to always return true, hence forcing a test on all open ports.

But this solution is not desired, it’s better to use a script argument to be able to force testing when really necessary.

I copied ssl-heartbleed.nse (SHA1 7540E31EF133226648616DF6534A8BD58C35A3D6) to ssl-heartbleed-force.nse and changed the portrule function like this:

<   return shortport.ssl(host, port) or sslcert.isPortSupported(port)
>   return stdnse.get_script_args(SCRIPT_NAME .. ".force") or shortport.ssl(host, port) or sslcert.isPortSupported(port)

With this change, ssl-heartbleed-force will behave exactly like ssl-heartbleed, unless you use script argument ssl-heartbleed-force.force, like this:

nmap --p443 --script ssl-heartbleed-force --script-args ssl-heartbleed-force.force cloudflarechallenge.com

This script argument will force the test on all open ports.

Friday 18 April 2014

Heartbleed: Testing From a Cisco IOS Router – ssltest.tcl

Filed under: My Software,Networking,Vulnerabilities — Didier Stevens @ 9:12

I wanted to know if I could exploit Heartbleed CVE-2014-0160 from a Cisco IOS router. So I wrote a Tcl script based on Jared Stafford’s Python program ssltest.py.

Turns out I can:

router#tclsh ssltest.tcl                         
Opening connection

Translating "cloudflarechallenge.com"...domain server ( [OK]
Sending handshake
Received TLS record Type: 0x16 Version: 0x0301 First data byte: 0x02 Length: 66
Received TLS record Type: 0x16 Version: 0x0301 First data byte: 0x0b Length: 6113
Received TLS record Type: 0x16 Version: 0x0301 First data byte: 0x0c Length: 331
Received TLS record Type: 0x16 Version: 0x0301 First data byte: 0x0e Length: 4
Sending malformed heartbeat request
Heartbeat response received
Received TLS record Type: 0x18 Version: 0x0301 First data byte: 0x02 Length: 16384
Heartbeat response dump:
02 40 00 6b c1 f4 ab d9  47 45 54 20 2f 20 48 54  .@.kC^AC4B+C^Y GET / HT
54 50 2f 31 2e 31 0d 0a  48 6f 73 74 3a 20 63 6c  TP/1.1.. Host: cl
6f 75 64 66 6c 61 72 65  63 68 61 6c 6c 65 6e 67  oudflare challeng
65 2e 63 6f 6d 0d 0a 43  6f 6e 6e 65 63 74 69 6f  e.com..C onnectio
6e 3a 20 6b 65 65 70 2d  61 6c 69 76 65 0d 0a 0d  n: keep- alive...
0a 2b 14 0d 6a c0 13 32  44 c1 a9 0f bf 5d dc 57  .+..jC^@.2 DC^AB).B?]C^\W
19 18 03 03 00 1b 34 f3  65 6b c1 f4 ab d8 01 ff  ......4C3 ekC^AC4B+C^X.C?
ff a6 8b c5 e2 2a b0 d6  b3 ff bd fc 9c 67 a7 83  C?B&.C^EC"*B0C^V B3C?B=C<.gB'.
40 72 10 38 5e 01 ff ff  f1 ca d2 f6 be 81 23 41  @r.8^.C?C? C1C C^RC6B>.#A
fb 8d 53 15 42 aa 52 bd  9e 5f 61 0a 08 08 08 08  C;.S.BB*RB= ._a.....
08 08 08 08 08 00 19 00  0b 00 0c 00 18 00 09 00  ........ ........
0a 00 16 00 17 00 08 00  06 00 07 00 14 00 15 00  ........ ........
04 00 05 00 12 00 13 00  01 00 02 00 03 00 0f 00  ........ ........
10 00 11 00 23 00 00 00  0f 00 01 01 0e 00 0d 00  ....#... ........
19 00 0b 00 0c 00 18 00  09 00 0a 00 16 00 17 00  ........ ........
08 00 06 00 07 00 14 00  15 00 04 00 05 00 12 00  ........ ........
13 00 01 00 02 00 03 00  0f 00 10 00 11 00 23 00  ........ ......#.
00 00 0d 00 20 00 1e 06  01 06 02 06 03 05 01 05  .... ... ........
02 05 03 04 01 04 02 04  03 03 01 03 02 03 03 02  ........ ........
01 02 02 02 03 00 0f 00  01 01 00 15 00 c2 00 00  ........ .....C^B..
00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ........ ........


00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ........ ........
00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ........ ........
Closing connection


Tested on: Cisco IOS Software, C880 Software (C880DATA-UNIVERSALK9-M), Version 15.1(4)M3, RELEASE SOFTWARE (fc1)

If you are interested, here is my Tcl PoC ssltest.tcl:
ssltest.zip (https)
MD5: 1B50D6A10637BB6472ED541733BBE68D
SHA256: DA744643CF06645DA9C27A7DD62853E15123D7481AE5D6776E6393A6312847E1

Thursday 10 April 2014

Heartbleed: Packet Capture – Full TLS

Filed under: Networking,Vulnerabilities — Didier Stevens @ 22:34

Yesterday I posted my heartbleed packet capture with an unencrypted heartbeat record.

Now I post a capture with full TLS session setup, hence here the heartbeat records are encrypted. I use heartbleed.c by HackerFantastic.

heartbleed_packet_capture_tls.zip (https)
MD5: 7D19146C2ACC28AFAD6E1FD217E908BB
SHA256: 7FDECDD05269731EDD57FFEE24323C672D620A533CD412089F055D6266C76164

Wednesday 9 April 2014

Heartbleed: Packet Capture

Filed under: Networking,Vulnerabilities — Didier Stevens @ 21:39

I could call this a cardiogram, but let’s not get carried away…

I took a packet capture of the heartbleed bug (CVE-2014-0160) in action: I have OpenSSL 1.0.1 14 March 2012 running on Apache2 (Ubuntu, VMware) and executed Jared Stafford’s ssltest.py script. One small modification to the script: I removed line 132 (the script transmits 2 heartbeat requests, I want only 1 request).

PS: as I expected, I didn’t find an entry in the Apache logs for this request.

heartbleed_packet_capture.zip (https)
MD5: 8302CDF315A91DD6FC32BB81AE0FB80D
SHA256: 7029CF9C2AF3CE7649501D15AD58439513F02B1B9ECD23343F6C6A6B2D87D344

Next Page »

Blog at WordPress.com.