<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Segmentation fault &#187; Reverse Engineering</title>
	<atom:link href="http://www.segmentationfault.fr/categories/reversing/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.segmentationfault.fr</link>
	<description>Projets d’un consultant en sécurité informatique</description>
	<lastBuildDate>Fri, 15 Feb 2019 08:02:10 +0000</lastBuildDate>
	<language>fr-FR</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.4.2</generator>
		<item>
		<title>Reversing Google Play and Micro-Protobuf applications</title>
		<link>http://www.segmentationfault.fr/publications/reversing-google-play-and-micro-protobuf-applications/</link>
		<comments>http://www.segmentationfault.fr/publications/reversing-google-play-and-micro-protobuf-applications/#comments</comments>
		<pubDate>Wed, 19 Sep 2012 20:11:23 +0000</pubDate>
		<dc:creator>Emilien Girault</dc:creator>
				<category><![CDATA[Publications]]></category>
		<category><![CDATA[Reverse Engineering]]></category>
		<category><![CDATA[androguard]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[protobuf]]></category>

		<guid isPermaLink="false">http://www.segmentationfault.fr/?p=946</guid>
		<description><![CDATA[I recently released a Google Play Unofficial Python API, which aims at providing a way for developers to query Google&#8217;s official Android application store. Such projects already exist, but they are all based on the previous version (&#171;&#160;Android Market&#160;&#187;), and are therefore limited. My goal was to adapt those projects and port them to the [...]]]></description>
			<content:encoded><![CDATA[<p>I recently released a <a href="https://github.com/egirault/googleplay-api/">Google Play Unofficial Python API</a>, which aims at providing a way for developers to query Google&rsquo;s official Android application store. Such projects already exist, but they are all based on the previous version (&laquo;&nbsp;Android Market&nbsp;&raquo;), and are therefore limited. My goal was to adapt those projects and port them to the last version of Google Play.</p>
<p>This article first highights the limitations of existing projects. Then it focuses on the official Android client for Google Play and its internals, based on a <a href="http://code.google.com/p/protobuf/">Protobuf</a> variant. Thanks to <a href="http://code.google.com/p/androguard/">Androguard</a> and its awesome static analysis features, I show how to automatically recover the <code>.proto</code> file of Google Play, enabling us to generate stubs for querying Google&rsquo;s servers. Finally, I quickly introduce the <a href="https://github.com/egirault/googleplay-api/">unofficial API</a>.<span id="more-946"></span></p>
<h3>Existing projects</h3>
<p>Google Play can be queried in two ways: using the <a href="https://play.google.com/store/apps">official website</a> or the Android client. The website contains pretty much all the useful information, such as app name and developer name, comments, last version number and release date, permissions required by the app, statistics, etc. I guess one could build a simple program that queries this website and parses the pages, but it would still have one limitation: you simply cannot download apps. Well, you can, but for this you will need an actual compatible phone, and as soon as you perform the install request, the application will get downloaded and installed on your phone. Then if you want to retrieve it in order to analyse it, you must plug in your phone and use <code>adb pull</code>. Some managed to get Google Play run within the emulator, but this is still a bit complicated and not straightforward: you need Java, <a href="http://developer.android.com/sdk/index.html">Android SDK</a>, customize your emulator ROM to embed Google Play, and script everyting yourself.</p>
<p>The main project I have been looking at is <a href="http://code.google.com/p/android-market-api/">android-market-api</a>, written in Java. Actually, I am a Python fan, and played much more with <a href="https://github.com/liato/android-market-api-py">its Python equivalent</a>. The goal of those projects is to simulate the network activity generated by the Android client, query Google Play servers, and parse the result. The underlying protocol used by Google Play is based on Google&rsquo;s <a href="http://code.google.com/p/protobuf/">Protocol Buffers</a>, aka <em>Protobuf</em>. For those who do not know, this library provides a way to encode messages in binary, compact blobs before sending them on the network, and decode them on the other side. The <a href="https://developers.google.com/protocol-buffers/docs/overview">documentation</a> contains plainty of details on the actual <a href="https://developers.google.com/protocol-buffers/docs/encoding?hl=fr">encoding format</a>, so I won&rsquo;t cover it. The only important thing to know about Protobuf is that it is much easier to decode messages if you know the structure of exchanged messages. Messages are composed of fields, each one having a tag, a name and a type. When encoded, a message embeds the tag, value and type (only basic types, or a generic &laquo;&nbsp;message&nbsp;&raquo; type) of each field, but <strong>not</strong> their names. Therefore, the semantics of each field must be guessed, and that is not always easy.</p>
<p>When Google Play Android client is able to query Google&rsquo;s servers and download APKs, all network communications are done with Protobuf and HTTP(S). The underlying Protobuf file used by the unofficial API projects (and based on Android Market) has been published as a <a href="http://code.google.com/p/android-market-api/source/browse/trunk/AndroidMarketApi/proto/market.proto"><code>.proto</code> file</a>. The unofficial API can forge some of those requests and interpret results. While playing with them, I have managed to search Android apps, but I could not always download them. Indeed, this version of the API requires a numeric « assetId » corresponding to the app you want to download. When trying to get appropriate assetIds using other API methods such as <code>search()</code>, I got non-numeric values, such as: <code>v2:com.fankewong.angrybirdsbackup2sd:1:4</code>. This type of value is rejected by Google Server when trying to download the app. Too bad&#8230;</p>
<h3>A first look at Google Play Android client</h3>
<p>The weird thing is that the non-numeric assetId problem occurs quite often, but not on all apps. I guess this is because Google updated their API when they switched to Google Play; those projects are using the old version of the API. The only way to have up-to-date information and be able to download any app would then be to analyse the updated Android client, and adapt existing projects.</p>
<p>Here we go! We retrieve <code>com.android.vending-1.apk</code> from an up-to-date Android phone using <code>adb</code>, and we use our favorite Android RE tools. A first look at class names highlights a pretty explicit <code>VendingProtos</code> class, under the <code>com.google.android.vending.remoting.protos</code> package. It contains references to a package named <code>com.google.protobuf.micro</code>, embedded within the app. This package contains classes used to encode and decode messages. It is actually part of a public project, named <a href="http://code.google.com/p/micro-protobuf/">micro-protobuf</a>, which is a lightweight version of Protobuf. However, the underlying protocol remains the same.</p>
<p>Most of network traffic is sent using HTTPS. After installing our own on CA onto the phone and setting up an interception proxy like Burp, we can sniff traffic. From a black-box approach, the exchanged data looks like a binary stream:</p>
<div id="attachment_950" class="wp-caption aligncenter" style="width: 533px"><a href="http://www.segmentationfault.fr/wp-content/uploads/2012/09/googleplay_burp1.png"><img class=" wp-image-950 " title="googleplay_burp" src="http://www.segmentationfault.fr/wp-content/uploads/2012/09/googleplay_burp1.png" alt="" width="523" height="462" /></a><p class="wp-caption-text">Capturing a Protobuf response with Burp</p></div>
<p>All we need now is the <code>.proto</code> file of Google Play to be able to decode it. But how can we get this file? It is unfortunately not embedded within the app, so we have to find another way. <a href="http://www.sysdream.com/reverse-engineering-protobuf-apps">A paper and a tool</a> have been published on the subject, but work only when the studied app or program embeds some kind of metadata, used by reflection features of Protobuf. This metadata is generally embedded in regular stubs generated with Google&rsquo;s standard protobuf compiler called <code>protoc</code>. However, this is not the case here since the Protobuf stubs embedded within Google Play Android client were not compiled with standard <code>protoc</code>. Micro-protobuf seems to remove this metadata, probably to make protocol reversing harder.</p>
<p>Anyway, is there a way to guess the structure of exchanged messages, just by having a look at the decompiled Java code of the app? Let&rsquo;s go back to the <code>VendingProtos</code> class. It is contains many subclasses, among which one named <code>AppDataProto</code>:</p>
<pre>public static final class AppDataProto extends MessageMicro
{
  private int cachedSize = -1;
  private boolean hasKey;
  private boolean hasValue;
  private String key_ = "";
  private String value_ = "";

  [...]

  public AppDataProto mergeFrom(CodedInputStreamMicro 
                                paramCodedInputStreamMicro)
    throws IOException
  {
    while (true)
    {
      int i = paramCodedInputStreamMicro.readTag();
      switch (i)
      {
      default:
        if (parseUnknownField(paramCodedInputStreamMicro, i))
          continue;
      case 0:
        return this;
      case 10:
        String str1 = paramCodedInputStreamMicro.readString();
        AppDataProto localAppDataProto1 = setKey(str1);
        break;
      case 18:
      }
      String str2 = paramCodedInputStreamMicro.readString();
      AppDataProto localAppDataProto2 = setValue(str2);
    }
  }

  public AppDataProto setKey(String paramString)
  {
    this.hasKey = 1;
    this.key_ = paramString;
    return this;
  }

  public AppDataProto setValue(String paramString)
  {
    this.hasValue = 1;
    this.value_ = paramString;
    return this;
  }

  [...]
}</pre>
<p>We can guess that this class represents a Micro-Protobuf message (the <code>extends MessageMicro</code> part) and that it has two string fields: <code>key</code> and <code>value</code>. Their tag can be extracted from the <code>mergeFrom()</code> method, which aims at decode incoming binary messages. It is composed of a main loop (<code>while(true)</code>) and a <code>switch</code> statement. Each case – except the first and second ones – corresponds to a field. The value of each case is actually the binary representation of the tag and type of the field. Everything is in the documentation; to skip the details, the actual value of each case is equal to <code>(tag &lt;&lt; 3) | type</code>. For instance, 10 stands for tag 1, type 2 (string). 18 means tag 2, string. Thus, the actual <code>.proto</code> file looks as follows:</p>
<pre>message AppDataProto {
  optional string key = 1;
  optional string value = 2;
}</pre>
<p>Actually type 2 is not exactly &laquo;&nbsp;string&nbsp;&raquo;, but any length-delimited field. It could be a string, a series of bytes, or an embedded message itself. In that case, the code looks like this:</p>
<pre>case 26:
  VendingProtos.AppDataProto localAppDataProto = new VendingProtos.AppDataProto();
  paramCodedInputStreamMicro.readMessage(localAppDataProto);
  DataMessageProto localDataMessageProto2 = addAppData(localAppDataProto);
  break;</pre>
<p>This field has a tag equal to 3 (26 &gt;&gt; 3) and is a message which name is <code>AppDataProto</code>. In order to get this sub-message structure, we would have to repeat the analysis process to the corresponding class, and so on.</p>
<h3>Automatic analysis</h3>
<p>We now have a way of recovering a message structure by analyzing the generated code. All we need now is automating the process. For this, we can use <a href="http://code.google.com/p/androguard/">Androguard</a>, a multi-purpose framework intended to make Android reversing easier. With Androguard, we can simply open an APK, decompile it, parse its Dalvik code, and do all sorts of things. Once installed, one can use the provided <code>androlyze</code> tool to dynamically interact with the framework, and then write a script to automate everything.</p>
<p>Androguard lets us easily browse the available classes and find those that extends <code>MessageMicro</code>.</p>
<pre>In [1]: apk = APK('com.android.vending-1.apk')
In [2]: dvm = DalvikVMFormat(apk.get_dex())
In [3]: vma = uVMAnalysis(dvm)
In [4]: proto_classes = filter(lambda c: "MessageMicro;" in c.get_superclassname(), dvm.get_classes())
In [5]: proto_class_names = map(lambda c: c.get_name(), proto_classes)</pre>
<p>Then we extract the <code>mergeFrom()</code> method of each class by filtering the method list generated by <code>dvm.get_methods_class(class_name)</code>. The basic block list of each method can be obtained with <code>vma.get_method(m).basic_blocks.gets()</code>.<br />
The first is usually the one that implements the switch instruction. In Dalvik, a switch is often represented as a <code>sparse-switch</code> instruction, which operand is a table composed of a list of values and offsets, called <code>sparse-switch-payload</code>. Here is an example:</p>
<pre>invoke-virtual v3, Lcom/google/protobuf/micro/CodedInputStreamMicro;-&gt;readTag()I
move-result v0
sparse-switch v0, +52 (0xa4)
[...]
sparse-switch-payload sparse-switch-payload 0:9 a:a 12:12 1a:1a 22:22 2a:2a 32:32 3a:3a 42:42 4a:4a</pre>
<p>Each (value, offset) tuple correspond to a case of the switch; if the value matches the compared register, then the execution continues to the corresponding offset. Once we are able to browse each case of the switch (and its target basic block), we can determine the name of each field and its type by examining the name of the corresponding accessors. For instance, here is a typical basic block:</p>
<pre>invoke-virtual v3, Lcom/google/protobuf/micro/CodedInputStreamMicro;-&gt;readString()Ljava/lang/String;
move-result-object v1
invoke-virtual v2, v1, L[...]AddressProto;-&gt;setCity(Ljava/lang/String;)L[...]AddressProto;
goto -25</pre>
<p>Each basic block contains two accessor calls: <code>readXXX()</code> and <code>setYYY()</code>. Their goal is to read an incoming series of bytes and initialize one field of the message. <code>XXX</code> corresponds to the type of the field (here, <em>string</em>), and <code>YYY</code> to its name (<em>city</em>).</p>
<p>The simplified analysis algorithm looks like:</p>
<pre>for each class that extends MessageMicro:
  get its mergeFrom() method
    find the sparse-switch instruction
    get the corresponding sparse-switch-payload
    index all values and offsets in a dict
    for each value, offset:
      tag = value &gt;&gt; 3
      get the target basic block using the offset
      find readXXX() and setYYY() calls
      type = XXX
      name = YYY
      index the tuple (tag, type, name)</pre>
<p>Then we only need to format the output in order to generate a parsable <code>.proto</code> file, dealing with nested messages and groups among other things.</p>
<p>I called the resulting script <a href="https://github.com/egirault/googleplay-api/blob/master/androguard/androproto.py"><code>androproto.py</code></a>. It is released with the API code; feel free to play with it. It is able to analyze the target app and print the recovered Profotuf file. I apologize for the dirty code; since Google Play is the only app using Micro-Protobuf that I&rsquo;ve analyzed, this script is pretty specific. But it should work with any app using this library, with a few changes. Its output on Google Play app looks like this:</p>
<pre>message AckNotificationResponse {
}
message AndroidAppDeliveryData {
  optional int64 downloadSize = 1;
  optional string signature = 2;
  optional string downloadUrl = 3;
  repeated AppFileMetadata additionalFile = 4;
  repeated HttpCookie downloadAuthCookie = 5;
  optional bool forwardLocked = 6;
  optional int64 refundTimeout = 7;
  optional bool serverInitiated = 8;
  optional int64 postInstallRefundWindowMillis = 9;
  optional bool immediateStartNeeded = 10;
  optional AndroidAppPatchData patchData = 11;
  optional EncryptionParams encryptionParams = 12;
}
message AndroidAppPatchData {
  optional int32 baseVersionCode = 1;
  optional string baseSignature = 2;
  optional string downloadUrl = 3;
  optional int32 patchFormat = 4;
  optional int64 maxPatchSize = 5;
}
[...]</pre>
<p>The resulting output is <em>almost</em> usable with <code>protoc</code>. Almost, because there is a duplicate message that you need to manually remove in order to make <code>protoc</code> happy. But after taking care of that detail, you have a working <a href="https://github.com/egirault/googleplay-api/blob/master/googleplay.proto"><code>googleplay.proto</code></a> that you can use to generate C++, Java and Python stubs for querying Google Play API!</p>
<h3>Building Google Play Unofficial Python API</h3>
<p>In order to parse Google Play protobuf messages, we dump each server response intercepted with Burp into a file, an use:</p>
<pre>protoc --decode=ResponseWrapper googleplay.proto &lt; dump.bin</pre>
<p><code>ResponseWrapper</code> is the root message type; it can be easily guessed by looking at the message names. Once we have a clue of what&rsquo;s received by the application, we can start building our own API. Since we need a valid auth token from Google server, we need first to authenticate. I simply reused the code from <a href="https://github.com/liato/android-market-api-py">android-market-api-py</a>. Once logged in, we need to deal with protobuf traffic. For most of API requests, the Android client does not send protobuf messages, but only simple GET or POST requests, such as <code>search?c=3&amp;q=%s</code>. In order to parse Protobuf responses, we use the generated Python module (<code>googleplay_pb2</code>):</p>
<pre>message = googleplay_pb2.ResponseWrapper.FromString(data)</pre>
<p>The resulting message can be browsed like a regular Python object. For some API methods, Google servers also return some <em>prefetch</em> data. A prefetch element contains a URL and raw data. It acts like a cache and can be dealt with pretty easily with a few lines of code.</p>
<p>The final API is pretty straightforward to use. Just follow the <a href="https://github.com/egirault/googleplay-api/blob/master/README.md">README</a>. First make sure to edit <code>googleplay.py</code> and insert your phone&rsquo;s <code>androidID</code>, then supply your Google credentials in <code>config.py</code>. You can use the provided scripts, producing CSV output, and prettify them with <code>pp</code>. Sorry for the following truncated output due to this blog&#8230;</p>
<pre>$ alias pp="column -s ';' -t"  # pretty-print CSV

$ python search.py earth | pp
Title                           Package name                            Creator                  Super Dev  Price    Offer Type  Version Code  Size     Rating  Num Downloads
Google Earth                    com.google.earth                        Google Inc.              1          Gratuit  1           53            8.6MB    4.46    10 000 000+
Terre HD Free Edition           ru.gonorovsky.kv.livewall.earthhd       Stanislav Gonorovsky     0          Gratuit  1           33            4.7MB    4.47    1 000 000+
Earth Live Wallpaper            com.seb.SLWP                            unixseb                  0          Gratuit  1           60            687.4KB  4.06    5 000 000+
Super Earth Wallpaper Free      com.mx.spacelwpfree                     Mariux                   0          Gratuit  1           2             1.8MB    4.41    100 000+
Earth And Legend                com.dvidearts.earthandlegend            DVide Arts Incorporated  0          5,99 €   1           6             6.8MB    4.82    50 000+
Earth 3D                        com.jmsys.earth3d                       Dokon Jang               0          Gratuit  1           12            3.4MB    4.05    500 000+
[...]

$ python categories.py | pp
ID                   Name
GAME                 Jeux
NEWS_AND_MAGAZINES   Actualités et magazines
COMICS               BD
LIBRARIES_AND_DEMO   Bibliothèques et démos
COMMUNICATION        Communication
ENTERTAINMENT        Divertissement
EDUCATION            Enseignement
FINANCE              Finance

$ python list.py 
Usage: list.py category [subcategory] [nb_results] [offset]
List subcategories and apps within them.
category: To obtain a list of supported catagories, use categories.py
subcategory: You can get a list of all subcategories available, by supplying a valid category

$ python list.py WEATHER | pp
Subcategory ID            Name
apps_topselling_paid      Top payant
apps_topselling_free      Top gratuit
apps_topgrossing          Les plus rentables
apps_topselling_new_paid  Top des nouveautés payantes
apps_topselling_new_free  Top des nouveautés gratuites

$ python list.py WEATHER apps_topselling_free | pp
Title                  Package name                                  Creator          Super Dev  Price    Offer Type  Version Code  Size    Rating  Num Downloads
La chaine météo        com.lachainemeteo.androidapp                  METEO CONSULT    0          Gratuit  1           8             4.6MB   4.38    1 000 000+
Météo-France           fr.meteo                                      Météo-France     0          Gratuit  1           11            2.4MB   3.63    1 000 000+
GO Weather EX          com.gau.go.launcherex.gowidget.weatherwidget  GO Launcher EX   0          Gratuit  1           25            6.5MB   4.40    10 000 000+
Thermomètre (Gratuit)  com.xiaad.android.thermometertrial            Mobiquité        0          Gratuit  1           60            3.6MB   3.78    1 000 000+

$ python permissions.py com.google.android.gm
android.permission.ACCESS_NETWORK_STATE
android.permission.GET_ACCOUNTS
android.permission.MANAGE_ACCOUNTS
android.permission.INTERNET
android.permission.READ_CONTACTS
android.permission.WRITE_CONTACTS
android.permission.READ_SYNC_SETTINGS
android.permission.READ_SYNC_STATS
android.permission.RECEIVE_BOOT_COMPLETED
[...]

$ python download.py com.google.android.gm
Downloading 2.7MB... Done

$ file com.google.android.gm.apk 
com.google.android.gm.apk: Zip archive data, at least v2.0 to extract</pre>
<h3>Conclusion</h3>
<p>Although there is no metadata within Micro-Protobuf applications, recovering <code>.proto</code> files is still doable and it can still be done automatically. The lack of obfuscation is clearly an advantage for an attacker, since all class and method names are easy to understand. Having a non-official Google Play API is handy for many reasons: performing statistics that aren&rsquo;t available on the official front-end, looking for plagiarism, automatic malware search / downloading / analysis (Androguard to the rescue)&#8230; Feel free to browse the <a href="https://github.com/egirault/googleplay-api/">source</a>, fork the project, and improve it!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.segmentationfault.fr/publications/reversing-google-play-and-micro-protobuf-applications/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Solution partielle du challenge SSTIC 2011</title>
		<link>http://www.segmentationfault.fr/securite-informatique/solution-partielle-challenge-sstic-2011/</link>
		<comments>http://www.segmentationfault.fr/securite-informatique/solution-partielle-challenge-sstic-2011/#comments</comments>
		<pubDate>Thu, 26 May 2011 17:10:31 +0000</pubDate>
		<dc:creator>Emilien Girault</dc:creator>
				<category><![CDATA[Reverse Engineering]]></category>
		<category><![CDATA[Sécurité informatique]]></category>

		<guid isPermaLink="false">http://www.segmentationfault.fr/?p=898</guid>
		<description><![CDATA[Cela fait un petit moment que je planche sur le célèbre challenge de SSTIC 2011. Étant donné que je ne pense pas en venir complétement à bout, voici quelques éléments de réponses qui résument ma progression. Certains m&#8217;ayant devancé, je vais tenter d&#8217;insister sur les parties non couvertes actuellement. Extraction des pistes Le but est [...]]]></description>
			<content:encoded><![CDATA[<p>Cela fait un petit moment que je planche sur le célèbre <a href="http://communaute.sstic.org/ChallengeSSTIC2011">challenge de SSTIC 2011</a>. Étant donné que je ne pense pas en venir complétement à bout, voici quelques éléments de réponses qui résument ma progression. <a href="http://exploitability.blogspot.com/2011/05/solution-partielle-du-challenge-sstic.html">Certains</a> m&rsquo;ayant devancé, je vais tenter d&rsquo;insister sur les parties non couvertes actuellement.</p>
<p><span id="more-898"></span></p>
<h3>Extraction des pistes</h3>
<p>Le but est d&rsquo;analyser une vidéo et d&rsquo;en extraire un mail. Il s&rsquo;agit d&rsquo;une vidéo au format MP4. Ne connaissant absolument pas ce format au moment où je me suis penché sur le challenge, j&rsquo;ai donc préféré me documenter sur le sujet. MP4 est en réalité un conteneur, et hérite de l&rsquo;<a href="http://en.wikipedia.org/wiki/ISO_base_media_file_format">ISO Base Media File Format</a>. Les <a href="http://standards.iso.org/ittf/PubliclyAvailableStandards/c051533_ISO_IEC_14496-12_2008.zip">specs</a> de ce dernier sont libres de droits, mais pas celles de MP4. Qu&rsquo;à cela ne tienne, elles suffisent amplement.</p>
<p>On y apprend que MP4 permet de stocker tout type d&rsquo;information : vidéo, son, et autre. Un fichier MP4 est décomposé en boxes, qui sont structurées sous la forme d&rsquo;un arbre. L&rsquo;outil MP4Box permet de les parser, mais je ne l&rsquo;ai découvert que tardivement ; aussi je me suis lancé dans l&rsquo;écriture d&rsquo;un outil manuel en Python.</p>
<pre>E:\Challenges\SSTIC2011&gt;boxes.py challenge
challenge {
  FileTypeBox(24 - ftyp - mp42 - 0),
  Box(4170138 - mdat),
  Box(277450 - mdat),
  Box(178748 - mdat),
  MovieBox(12507 - moov) {
    Box(108 - mvhd),
    TrackBox(5982 - trak - 0 ) {
      Box(92 - tkhd),
      SsticBox(12 - ssti)[   ?ssti    ],
      MediaBox(5822 - mdia) {
        Box(32 - mdhd),
        HandlerBox(33 - hdlr - vide -  ),
        MediaInformationBox(5749 - minf) {
          Box(20 - vmhd),
          DataInformationBox(36 - dinf) {
            DataReferenceBox(28 - dref) {
              1 entries
              DataEntryUrlBox(12 - url  - flags: 000001, url: )
            }
          },
          SampleTableBox(5685 - stbl) {
            SampleDescriptionBox(181 - stsd) {
              1 entries
              VisualSampleEntry(165 - mp4v - index: 1) {
                size: 640x480
                resolution: 0x00480000/0x00480000
                compressorname:
                depth: 0018

              }
            },
            Box(3248 - stts),
            SampleSizeBox(2092 - stsz) {
              sample_size = 0
              sample_count = 518

            },
            SampleToChunkBox(40 - stsc) {
              2 entries
            },
            ChunkOffsetBox(88 - stco) {
              18 entries
            },
            Box(28 - stss)
          }
        }
      },
      Box(48 - edts)
    },
    TrackBox(3492 - trak - 1 ) {
      Box(92 - tkhd),
      MediaBox(3372 - mdia) {
        Box(32 - mdhd),
        HandlerBox(33 - hdlr - soun -  ),
        MediaInformationBox(3299 - minf) {
          Box(16 - smhd),
          DataInformationBox(36 - dinf) {
            DataReferenceBox(28 - dref) {
              1 entries
              DataEntryUrlBox(12 - url  - flags: 000001, url: )
            }
          },
          SampleTableBox(3239 - stbl) {
            SampleDescriptionBox(103 - stsd) {
              1 entries
              Box(87 - mp4a)
            },
            Box(24 - stts),
            SampleSizeBox(2980 - stsz) {
              sample_size = 0
              sample_count = 740

            },
            SampleToChunkBox(40 - stsc) {
              2 entries
            },
            ChunkOffsetBox(84 - stco) {
              17 entries
            }
          }
        }
      },
      UserDataBox(20 - udta) {
        NameBox(12 - name -    ?name    )
      }
    },
    TrackBox(2917 - trak - 2 ) {
      Box(92 - tkhd),
      MediaBox(2817 - mdia) {
        Box(32 - mdhd),
        HandlerBox(45 - hdlr - data - SsticHandler ),
        MediaInformationBox(2732 - minf) {
          Box(12 - nmhd),
          DataInformationBox(36 - dinf) {
            DataReferenceBox(28 - dref) {
              1 entries
              DataEntryUrlBox(12 - url  - flags: 000001, url: )
            }
          },
          SampleTableBox(2676 - stbl) {
            SampleDescriptionBox(32 - stsd) {
              1 entries
              ElfEntry(16 - elf  - index: 1)
            },
            Box(24 - stts),
            SampleToChunkBox(1552 - stsc) {
              128 entries
            },
            SampleSizeBox(532 - stsz) {
              sample_size = 0
              sample_count = 128

            },
            ChunkOffsetBox(528 - stco) {
              128 entries
            }
          }
        }
      }
    }
  }
}</pre>
<p>Le fichier est ainsi composé de 3 tracks : une video, une piste son, et une piste apparemment inconnue. On peut extraire chacune de ces pistes en utilisant les méta-données du fichier, et en particulier les tables STSZ, STSC et STCO. L&rsquo;algorithme d&rsquo;extraction n&rsquo;est pas bien complexe et peut être trouvé grâce aux spécifications.</p>
<p>La piste audio est en clair, mais pas très utile &#8211; quelque chose qui ressemble à des frappes sur un clavier. La vidéo est illisible, a priori chiffrée grâce à des DRM. Enfin, la piste 3 n&rsquo;est autre qu&rsquo;un fichier ELF !</p>
<h3>Analyse du fichier ELF</h3>
<p>Avec IDA, on s&rsquo;aperçoit rapidement que le binaire n&rsquo;est autre qu&rsquo;un plugin VLC. En effet, il comporte tous les symboles propres à ce type de plugin.On suppose que ce plugin est nécessaire à la lecture de ladite vidéo. Les sources de VLC permettant de se rendre compte qu&rsquo;il s&rsquo;agit en fait d&rsquo;une version modifiée du plugin officiel libmp4.so. Un certain nombre de fonctions ont été ajoutées :</p>
<ul>
<li>sstic_drm_init()</li>
<li>sstic_read_secret1(char*dir, char* buf1)</li>
<li>sstic_check_secret1(char*buf1)</li>
<li>sstic_read_secret2(char*dir, char*buf2)</li>
<li>sstic_check_secret2(char*buf2)</li>
<li>sstic_lame_derive_key(char* bufKey, char* buf1, char* buf2)</li>
</ul>
<p>Il est possible de débuger le plugin en le plaçant dans le dossier des librairies de VLC sur une machine Linux, puis en s&rsquo;attachant à VLC avec GDB.</p>
<p>En gros, sstic_drm_init() est appelée dès l&rsquo;initialisation du plugin, et est chargée d&rsquo;appeler les fonctions suivantes. Le but de ce plugin est de déchiffrer la vidéo a l&rsquo;aide d&rsquo;une clé générée à partir de deux fichiers, secret1.dat et secret2.dat situés dans le dossier ~/sstic2011/. Voici un schéma expliquant l&rsquo;algorithme reversé à grand coup d&rsquo;IDA et Hex Rays :</p>
<p style="text-align: center;">&nbsp;</p>
<div class="mceTemp mceIEcenter" style="text-align: left;">
<dl id="attachment_900" class="wp-caption aligncenter" style="width: 545px;">
<dt class="wp-caption-dt"><a href="http://www.segmentationfault.fr/wp-content/uploads/2011/05/sstic2011.png"><img class="size-full wp-image-900  " title="sstic2011" src="http://www.segmentationfault.fr/wp-content/uploads/2011/05/sstic2011.png" alt="Algorithme de déchiffrement" width="535" height="119" /></a></dt>
<dd class="wp-caption-dd">Algorithme de déchiffrement</dd>
</dl>
</div>
<p style="text-align: left;">Pour résumer :</p>
<ul>
<li>secret1.dat (32 octets) est lu, puis son emprunte MD5 est calculée et comparée avec une constante présente en dur dans le binaire</li>
<li>secret2.dat (1024 octets) est lu, puis déchiffré à l&rsquo;aide d&rsquo;un algorithme symétrique maison (cf plus bas) et d&rsquo;une clé fixe stockée. Le plaintext résultant est comparé à un plaintext lui aussi stocké en dur.</li>
<li>Si les deux tests précédents réussissent, les 2 secrets originaux sont passés à la fonction sstic_lame_derive_key, qui ne fait que les xorrer pour finalement obtenir un secret de 32 octets (pour secret1.dat, qui fait 1024 octets, tous les blocs de 32 octet sont xorrés)</li>
<li>Le secret résultant est utilisé comme une clé RC2 qui servira à déchiffrer chaque sample de la vidéo lors de sa lecture. Au passage, l&rsquo;implémentation RC2 est la même que celle d&rsquo;OpenSSL, pas de soucis de ce côté la.</li>
</ul>
<p>Autrement dit, il nous faut nécessairement secret1 et secret2 si l&rsquo;on veut déchiffrer la vidéo. C&rsquo;est là que les choses se compliquent&#8230;</p>
<h3>Secret2.dat : Crypto + MMX</h3>
<p style="text-align: left;">Pour trouver secret2.dat, on remarque qu&rsquo;il &laquo;&nbsp;suffit&nbsp;&raquo; d&rsquo;inverser l&rsquo;algorithme de déchiffrement implémenté dans la fonction &laquo;&nbsp;decrypt&nbsp;&raquo;, pour trouver le chiffré qui donnera le bon clair une fois déchiffré. Cependant, il ne s&rsquo;agit pas directement d&rsquo;un algorithme standard&#8230; Celui-ci utilise massivement les instructions Intel MMX, qui manipulent des entiers sur 128 bits. Le code ASM est une horreur, et je ne parle pas du listing généré par Hex Rays&#8230;</p>
<p style="text-align: center;">&nbsp;</p>
<div class="mceTemp mceIEcenter" style="text-align: left;">
<dl id="attachment_901" class="wp-caption aligncenter" style="width: 599px;">
<dt class="wp-caption-dt"><a href="http://www.segmentationfault.fr/wp-content/uploads/2011/05/sstic2011_decrypt.png"><img class="size-full wp-image-901  " title="sstic2011_decrypt" src="http://www.segmentationfault.fr/wp-content/uploads/2011/05/sstic2011_decrypt.png" alt="Pseudo-code de decrypt()" width="589" height="244" /></a></dt>
<dd class="wp-caption-dd">Pseudo-code partiel de decrypt()</dd>
</dl>
</div>
<p style="text-align: left;">Pas moins de 351 variables, plus de 2100 lignes de code, et des opérations logiques dans tous les sens. Miam ! Bon, on prend notre courage à deux mains, et on y va. Premièrement, on remarque l&rsquo;utilisation de constantes un peu particulières.</p>
<pre style="text-align: left;">for ( sum = 0x9E3779B9 * a3; ; sum += -0x9E3779B9u ) {</pre>
<p style="text-align: left;">Notre ami Google nous indique qu&rsquo;une boucle faisant intervenir de telles constantes est utilisée par les algorithmes <a href="http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm">TEA</a> et <a href="http://en.wikipedia.org/wiki/XTEA">XTEA</a>. Cependant, ces algorithmes ont une taille de clé de 128 bits, et une taille de bloc de 64 bits, alors qu&rsquo;ici, la clé fait 2048 octets&#8230;</p>
<p style="text-align: left;">Deuxièmement, on s&rsquo;aperçoit qu&rsquo;il y a beaucoup de code redondant dans ce listing. Cela est du à l&rsquo;utilisation intensive des techniques de <a href="http://en.wikipedia.org/wiki/Loop_unwinding">loop unrolling</a>, qui consistent en gros à minimiser le nombre de tours dans une boucle en écrivant n fois la même instruction dans un tour (appliqué à des données différentes).</p>
<p style="text-align: left;">Troisièmement, en supposant qu&rsquo;il s&rsquo;agisse de l&rsquo;algorithme TEA, la logique voudrait qu&rsquo;on trouve des opérations + et -. Or ce n&rsquo;est pas le cas ici ; on a affaire à des opérations logiques uniquement. Après on long moment de réflexion, je me suis rendu compte que ces opérations logiques servent en réalité à propager des retenues&#8230; utilisées justement lors des opérations d&rsquo;addition et soustraction. On se rend ainsi compte que chaque addition a été remplacé par une série de xor, not et and équivalente au schéma suivant :</p>
<p style="text-align: center;">&nbsp;</p>
<div id="attachment_904" class="wp-caption aligncenter" style="width: 436px"><a href="http://www.segmentationfault.fr/wp-content/uploads/2011/05/additionneur.gif"><img class="size-full wp-image-904 " title="Additionneur" src="http://www.segmentationfault.fr/wp-content/uploads/2011/05/additionneur.gif" alt="Additionneur" width="426" height="255" /></a><p class="wp-caption-text">Additionneur</p></div>
<p style="text-align: left;">Attention, chaque fil ici représente non pas 1 bit, mais 128, soit 16 octets ! En gros, l&rsquo;auteur du challenge a réimplémenté son propre + et &#8211; en recodant ces 2 opérations, prenant comme unité 128 bits de données. Soit !</p>
<p style="text-align: left;">En utilisant toutes ces information, et une bonne dose de motivation, j&rsquo;ai pu confirmé qu&rsquo;il s&rsquo;agit bien de l&rsquo;algorithme TEA, qui finalement n&rsquo;est pas si complexe que ça (cf Wikipédia) :</p>
<pre style="text-align: left;">
<pre>void decrypt (uint32_t* v, uint32_t* k) {
    uint32_t v0=v[0], v1=v[1], sum=0xC6EF3720, i;  /* set up */
    uint32_t delta=0x9e3779b9;                     /* a key schedule constant */
    uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */
    for (i=0; i&lt;32; i++) {                         /* basic cycle start */
        v1 -= ((v0&lt;&lt;4) + k2) ^ (v0 + sum) ^ ((v0&gt;&gt;5) + k3);
        v0 -= ((v1&lt;&lt;4) + k0) ^ (v1 + sum) ^ ((v1&gt;&gt;5) + k1);
        sum -= delta;
    }                                              /* end cycle */
    v[0]=v0; v[1]=v1;
}</pre>
<p>A la différence près que les uint32 de ce code doivent être remplacés par des blocs de 16 octets. Autrement dit, toutes les tailles doivent être multipliées par 4. Cela n&rsquo;étant pas standard, il n&rsquo;existe aucune librairie (à ma connaissance) faisant cela. Il est donc nécessaire de recoder l&rsquo;opération encrypt() à la main !</p>
<p>Pour cela, j&rsquo;ai copié/collé le code d&rsquo;Hex Rays dans un fichier .c, puis je l&rsquo;ai adapté afin qu&rsquo;il compile dans un premier temps avec Visual Studio. Puis je l&rsquo;ai optimisé en taille (suppression du loop unrolling). Et enfin, je l&rsquo;ai inversé afin d&rsquo;effectuer non pas un déchiffrement, mais un chiffrement.</p>
<p>On lance tout ça avec le plaintext et la clé tous deux stockés en dur dans le programme, et on obtient un secret2.dat valide. J&rsquo;ai pu le confirmer en debuggant le plugin avec GDB, un breakpoint étant posé au bon endroit dans sstic_check_secret2(). Et une étape de passée !</p>
<h3>Secret1.dat : MySQL, UDF and rock&rsquo;n roll</h3>
<p>Ici, contrairement à secret2.dat, nous ne disposons que du MD5 du fichier. Bruteforcer 32 octets étant une perte de temps, il doit donc y avoir un moyen de l&rsquo;obtenir&#8230; J&rsquo;ai séché pendant pas mal de temps, et c&rsquo;est là que l&rsquo;appel à un ami a servi (merci Dad) !</p>
<p>Ceux qui ont regardé le fichier original de la vidéo dans un éditeur auront certainement remarqué le &laquo;&nbsp;introduction.txt&nbsp;&raquo;. Il s&rsquo;agit en réalité du nom d&rsquo;un fichier texte qui a été gzipé et embarqué dans la vidéo. Malheureusement, il n&rsquo;est pas en un seul bloc, mais en plusieurs, qui ont été éparpillées dans le fichier, aux endroits non utilisés (un fichier MP4 peut contenir du &laquo;&nbsp;vide&nbsp;&raquo;). Lors de notre opération d&rsquo;extraction des pistes, nous nous sommes focalisés sur les données utiles du fichier. Et si nous faisions l&rsquo;inverse ? Le fichier gzip peut être obtenu justement grâce à ce procédé, c&rsquo;est-à-dire en suppriment tous les chunks non utilisés du fichier.</p>
<p>Une fois décompressé, on obtient la notice suivante :</p>
<pre>Cher participant,
Le développeur étourdi d'un nouveau système de gestion de base de données
révolutionnaire a malencontreusement oublié quelques fichiers sur son serveur
web. Une partie des sources et des objets de ce SGBD pourraient se révéler
utile afin d'exploiter une éventuelle vulnérabilité.
Sauras-tu en tirer profit pour lire la clé présente dans le fichier
secret1.dat ?
url      : http://XX.XX.XX.XX/ login    : sstic2011 password : XXXXXXXX
--------------------------------------------------------------------------------
Toute attaque par déni de service est formellement interdite. Les organisateurs
du challenge se réservent le droit de bannir l'adresse IP de toute machine
effectuant un déni de service sur le serveur.
--------------------------------------------------------------------------------</pre>
<p>On se connecte sur l&rsquo;URL fournie, et on récupère trois fichiers :</p>
<ul>
<li>udf.so</li>
<li>udf.c</li>
<li>lobster_dog.jpg (s&rsquo;il s&rsquo;agit d&rsquo;une blague de l&rsquo;auteur du challenge, je n&rsquo;ai pas du la saisir <img src='http://www.segmentationfault.fr/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </li>
</ul>
<p>UDF signifie User Defined Functions ; il s&rsquo;agit de plugins MySQL permettant de rajouter des fonctions sur un serveur. Le port 3306 du serveur hébergeant ces fichiers est ouverts, et les mêmes identifiants fonctionnent. Il y a donc bien quelque chose à exploiter ici. Fouillons un peu :</p>
<pre>mysql&gt; select version();
+------------------+
| 1.3.337sstic2011 |
+------------------+
| 1.3.337sstic2011 |
+------------------+
1 row in set (0.56 sec)

mysql&gt; show databases;
+----------+
| Database |
+----------+
|   system |
|    sstic |
+----------+
2 rows in set (0.22 sec)

mysql&gt; use sstic;
Database changed
mysql&gt; show tables;
+--------+
| Tables |
+--------+
|  users |
+--------+
1 row in set (0.20 sec)

mysql&gt; select * from users;
+------+--------+----------------------------------+
| id   | login  | password                         |
+------+--------+----------------------------------+
| 0    | root   | 3e47b75000b0924b6c9ba5759a7cf15d |    =&gt; nothing
| 1    | guest  | a76637b62ea99acda12f5859313f539a |    =&gt; interesting
| 2    | nobody | 6c92285fa6d3e827b198d120ea3ac674 |    =&gt; here
| 3    | *      | 5058f1af8388633f609cadb75a75dc9d |    =&gt; .
+------+--------+----------------------------------+
4 rows in set (0.28 sec)

mysql&gt; use system;
Database changed
mysql&gt; show tables;
+-------------+
| Tables      |
+-------------+
| information |
+-------------+
1 row in set (0.23 sec)

mysql&gt; select * from information;
+------------------+----------+
| version          | security |
+------------------+----------+
| 1.3.337sstic2011 | SECCOMP  |
+------------------+----------+
1 row in set (0.22 sec)</pre>
<p>Visiblement SECCOMP est activé, ce qui nous empêchera d&rsquo;effectuer des appels systèmes autres que read() et write() sur des fichiers déjà ouverts. Croisons donc les doigts pour que le serveur ouvre secret1.dat en lecture avant d&rsquo;activer ce mode <img src='http://www.segmentationfault.fr/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Une petite analyse du .c (analysé en partie sur <a href="http://exploitability.blogspot.com/2011/05/solution-partielle-du-challenge-sstic.html">ce blog</a>) montre que celui-ci possède un bug dans la gestion d&rsquo;un champ union, et est vulnérable à deux failles :</p>
<ul>
<li>Une fuite d&rsquo;information qui permet d&rsquo;afficher n&rsquo;importe quelle adresse mémoire</li>
<li>Une exécution de code à distance</li>
</ul>
<p>Cependant, ces deux failles restents assez complexes à exploiter compte tenu du fait que nous sommes dans l&rsquo;impossibilité de débugger le serveur distant, et que le udf.so donné ne parvient pas à se lancer sur un serveur MySQL standard. Au moindre problème, la connexion est coupée et il faut tout recommencer.</p>
<p>Toutefois, en exploitant la première faille et son bug de typage, on se rend compte que l&rsquo;on peut obtenir des adresses mémoires :</p>
<pre>mysql&gt; select abs('lala');
+-----------+
| 153315552 |
+-----------+
| 153315552 |
+-----------+
1 row in set (0.59 sec)

mysql&gt; select concat("", 153315552);
+------+
| lala |
+------+
| lala |
+------+
1 row in set (0.20 sec)</pre>
<p>En réalité, 153315552 n&rsquo;est pas directement l&rsquo;adresse de la chaîne &laquo;&nbsp;lala&nbsp;&raquo;, mais l&rsquo;adresse de la structure &laquo;&nbsp;val&nbsp;&raquo; correspondante, qui ressemble à ceci :</p>
<pre>struct val {
  int unknown;
  union value {
    int i;                    //4
    void * p;                 //4
  }
  int size;                   //8
  int *(expand)(val*);        //12
}</pre>
<p>En gros, on peut demander à la fonction concat() de traiter une fausse structure située à une adresse choisie. Selon que l&rsquo;on passe cette structure en 1er ou 2ème argument à la fonction, cela débouche soit sur une exécution de code (pointeur expand) ou sur une fuite (pointeur p).</p>
<p>Étant donné le caractère &laquo;&nbsp;blind&nbsp;&raquo; de cette exploitation, j&rsquo;ai préféré dans un premier temps dumper le binaire du serveur MySQL. Celui-ci est chargé de façon standard à l&rsquo;adresse 0&#215;08048000. En forgeant une fausse structure et en la passant à substring(), elle aussi vulnérable, et en scriptant tout ça en python, et on récupère ce fameux binaire.</p>
<p>Seul soucis : celui-ci n&rsquo;a aucun symbole et aucune table de section référencée. Impossible de le lancer, donc. En tout cas, on voit bien qu&rsquo;il y a une référence à secret1.dat (les noms de fonction ne sont pas d&rsquo;origine, mais ont été devinés).</p>
<pre>int __cdecl my_open_secret1()
{
 int fd; // [sp+1Ch] [bp-Ch]@1

 fd = ((int (__cdecl *)(_DWORD, _DWORD))my_open)("secret1.dat", 0);
 if ( fd == -1 )
 sub_8048C28();
 return fd;
}</pre>
<p>L&rsquo;appel à open() est en réalité un appel à une fonction dans la section .plt du programme, qui utilise elle-même la section .got. Pour récupérer le code de cette fonction, j&rsquo;ai utilisé toujours cette même faille de fuite d&rsquo;information. Au final, l&rsquo;adresse référencée est dans une librairie (adresse 0xb7XXXXXX). Son code est constitué d&rsquo;instructions <em>mov</em> pour digitaliser des registres généraux, suivies d&rsquo;un <em>call *%gs:0&#215;10</em>, qui n&rsquo;est autre qu&rsquo;un appel système (le code appelé débouche certainement sur l&rsquo;instruction <em>sysenter </em>ou<em> int 0&#215;80</em>). La valeur d&rsquo;eax, 5, permet de vérifier qu&rsquo;il s&rsquo;agit bien de sys_open. Le file descriptor retourné est stocké à l&rsquo;adresse 0x0804F18C, est n&rsquo;est autre que 3 (0, 1 et 2 correspondant respectivement à stdin, stdout et stderr).</p>
<p>Tout ce qu&rsquo;il reste à faire, c&rsquo;est donc trouver un moyen de faire exécuter un read() sur le file descriptor de secret1.dat afin de lire ses 32 octets qui nous manquent pour déchiffrer cette fichue vidéo. Seulement, je ne vois qu&rsquo;une seule technique pour cela, et je n&rsquo;ai pas eu le temps de la tester. La protection NX étant activée (pour s&rsquo;en rendre compte il suffit de voire que l&rsquo;exécution d&rsquo;un ret situé dans le heap foire, alors qu&rsquo;elle fonctionne dans la section .text), la seule solution reste à mon avis le Return Oriented Programming. Sauf que ne disposant ni d&rsquo;une forte expérience dans cet art ancestral, ni d&rsquo;une quantité de temps suffisante (les <a href="http://www.rssil.org/challenge-securite">RSSIL</a> approchent !), je n&rsquo;ai pas eu le temps de creuser plus loin. Dommage, car j&rsquo;ai vraiment l&rsquo;impression d&rsquo;être tout près du but&#8230; à un appel système près <img src='http://www.segmentationfault.fr/wp-includes/images/smilies/icon_sad.gif' alt=':(' class='wp-smiley' /> . A supposer bien sûr que le déchiffrement de la vidéo est l&rsquo;étape finale&#8230; (là, je sens comme un doute m&rsquo;envahir)</p>
<h3>To be continued</h3>
<p>Comme l&rsquo;année dernière, ce challenge réunit à la fois du parsing, du reverse engineering et de la crypto, mais en plus une partie exploitation de service à distance, sur laquelle j&rsquo;ai buté. J&rsquo;attends avec impatience la solution de l&rsquo;étape manquante, à savoir la récupération de secret1.dat. En tout cas, je ne regrette pas avoir passé de nombreuses heures (jours, en fait) sur cette épreuve, qui m&rsquo;aura fait quelques nœuds aux neurones.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.segmentationfault.fr/securite-informatique/solution-partielle-challenge-sstic-2011/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Bypassing SEHOP on Windows 7</title>
		<link>http://www.segmentationfault.fr/securite-informatique/bypassing-sehop-on-windows-7/</link>
		<comments>http://www.segmentationfault.fr/securite-informatique/bypassing-sehop-on-windows-7/#comments</comments>
		<pubDate>Mon, 21 Dec 2009 12:59:28 +0000</pubDate>
		<dc:creator>Emilien Girault</dc:creator>
				<category><![CDATA[Reverse Engineering]]></category>
		<category><![CDATA[Sécurité informatique]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[hacking]]></category>
		<category><![CDATA[seven]]></category>

		<guid isPermaLink="false">http://www.segmentationfault.fr/?p=740</guid>
		<description><![CDATA[La protection SEHOP introduite dans Windows Vista et 2008 permet de protéger les applications contre les exploitations de buffer-overflows classiques. Celles-ci consistent en général à écraser non seulement une adresse de retour, mais aussi la structure SEH gérant les exceptions provoquées par l&#8217;application, dans le but de rediriger le flux d&#8217;exécution vers un shellcode. La [...]]]></description>
			<content:encoded><![CDATA[<p>La protection SEHOP <a href="http://blogs.technet.com/srd/archive/2009/02/02/preventing-the-exploitation-of-seh-overwrites-with-sehop.aspx">introduite</a> dans Windows Vista et 2008 permet de protéger les applications contre les exploitations de buffer-overflows classiques. Celles-ci consistent en général à écraser non seulement une adresse de retour, mais aussi la structure SEH gérant les exceptions provoquées par l&rsquo;application, dans le but de rediriger le flux d&rsquo;exécution vers un shellcode. La protection SEHOP empêche ce type d&rsquo;exploitation en parcourant au préalable la chaîne des structures SEH et en s&rsquo;assurant qu&rsquo;elle soit valide. Jusqu&rsquo;à maintenant, elle était considérée par beaucoup comme inviolable. Microsoft ont d&rsquo;ailleurs décidé de l&rsquo;activer par défaut dans Windows 2008, ainsi que dans Windows Vista et 7 sous forme de fix.<span id="more-740"></span></p>
<p>Or, deux collègues de <a href="http://www.sysdream.com/">Sysdream</a>, Stéfan Leberre (<a href="http://www.ghostsinthestack.org">Heurs</a>) et Damien Cauquil (<a href="http://www.virtualabs.fr">Virtualabs</a>), viennent de trouver une méthode permettant de la contourner sous certaines conditions. Leur article ainsi que leur Proof Of Concept est disponible sur le site de Sysdream :</p>
<ul>
<li><a href="http://www.sysdream.com/articles/sehop_en.pdf">L&rsquo;article Bypassing SEHOP</a></li>
<li><a href="http://www.sysdream.com/SEHOP.zip">Proof Of Concept fonctionnant sous Windows 7</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.segmentationfault.fr/securite-informatique/bypassing-sehop-on-windows-7/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>RDTSC hooking sous Linux : théorie et pratique</title>
		<link>http://www.segmentationfault.fr/securite-informatique/rdtsc-hooking-linux/</link>
		<comments>http://www.segmentationfault.fr/securite-informatique/rdtsc-hooking-linux/#comments</comments>
		<pubDate>Tue, 14 Jul 2009 12:30:35 +0000</pubDate>
		<dc:creator>Emilien Girault</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Reverse Engineering]]></category>
		<category><![CDATA[Sécurité informatique]]></category>
		<category><![CDATA[hacking]]></category>
		<category><![CDATA[ring 0]]></category>
		<category><![CDATA[x86]]></category>

		<guid isPermaLink="false">http://www.segmentationfault.fr/?p=688</guid>
		<description><![CDATA[L&#8217;architecture x86 possède des subtilités parfois méconnues de beaucoup de développeurs. En effet, il existe une instruction assez spéciale, RDTSC, qui renvoie le nombre de cycles d&#8217;horloge depuis le démarrage du processeur. En 2007, un chercheur d&#8217;IBM présente au Black Hat une technique de hook basée sur cette instruction. En effet, il se trouve qu&#8217;il [...]]]></description>
			<content:encoded><![CDATA[<p>L&rsquo;architecture x86 possède des subtilités parfois méconnues de beaucoup de développeurs. En effet, il existe une instruction assez spéciale, RDTSC, qui renvoie le nombre de cycles d&rsquo;horloge depuis le démarrage du processeur. En 2007, un chercheur d&rsquo;IBM <a href="https://www.blackhat.com/presentations/bh-usa-07/Yason/Whitepaper/bh-usa-07-yason-WP.pdf">présente </a>au Black Hat une technique de hook basée sur cette instruction. En effet, il se trouve qu&rsquo;il existe un flag dans le registre de contrôle CR4 permettant de désactiver cette instruction en ring 3, et de déclencher une exception #GP (int 13) lors de son appel. Via un hook de l&rsquo;IDT par un driver codé maison, il devient donc possible de détourner les appels ring 3 à RDTSC, de filtrer les résultats et imaginer toutes sortes de choses. D&rsquo;autant plus que RDTSC est couramment utilisée dans des application ayant trait à la sécurité, comme les méthodes d&rsquo;anti-debugging ou de génération de nombres aléatoires&#8230;</p>
<p><span id="more-688"></span></p>
<p>Pour cet article, on se propose d&rsquo;écrire un driver qui effectuera ce hook et qui détournera RDTSC afin de rendre les valeurs 11223344 et 55667788 respectivement dans EAX et EDX lorsqu&rsquo;on l&rsquo;appelle. Je présente en premier lieu la théorie nécessaire pour l&rsquo;attaque, puis décris comment l&rsquo;implémenter sous Linux. Enfin, je détaille une difficulté majeure à laquelle on peut faire face sur les distributions récentes telles qu&rsquo;ArchLinux : le flag TIF_NOTSC.</p>
<h3>L&rsquo;instruction RDTSC et le flag TSD</h3>
<p>RDTSC signifie &laquo;&nbsp;ReaD TimeStamp Counter&nbsp;&raquo;, autrement dit elle permet de lire le compteur de temps du processeur, incrémenté à chaque cycle d&rsquo;horloge. Ce compteur n&rsquo;est autre que le MSR IA32_TIME_STAMP_COUNTER (cf <a href="http://www.intel.com/products/processor/manuals/">manuel 3B d&rsquo;Intel</a>, section 18.11). Celui-ci fait 64 bits et est retourné dans EDX et EAX lors de l&rsquo;appel à RDTSC. Les applications classiques s&rsquo;en servent généralement pour :</p>
<ul>
<li>Effectuer des mesures de performance (benchmark) sans passer par les fonctions du noyau</li>
<li>Générer des nombres pseudo-aléatoires, à cause du caractère à priori non prévisible de ce compteur (surtout des bits de poids faible)</li>
<li>Détecter des débogueur en mesurant des deltas entre deux instructions fixes ; si un débogueur est présent et qu&rsquo;un breakpoint a été posé (ou que le mode step-by-step a été utilisé), le temps écoulé sera beaucoup plus long donc il est facile à l&rsquo;application de quitter.</li>
</ul>
<p>Cependant, ce n&rsquo;est pas exactement comme cela qu&rsquo;est décrit l&rsquo;instruction RDTSC dans le <a href="http://www.intel.com/products/processor/manuals/">manuel 2B d&rsquo;Intel</a>. En effet, on peut y lire le pseudo-code suivant :</p>
<pre>IF (CR4.TSD = 0) or (CPL = 0) or (CR0.PE = 0)
THEN EDX:EAX ? TimeStampCounter;
ELSE (* CR4.TSD = 1 and (CPL = 1, 2, or 3) and CR0.PE = 1 *)
#GP(0);
FI;</pre>
<p>On y apprend que le registre CR4 possède un flag TSD qui, s&rsquo;il est activé, provoquerait une exception lorsque RDTSC est appelé dans un ring supérieur à 0 (mode protégé). Cette exception est la General Protection Fault, notée #GP et définie à l&rsquo;index 13 dans l&rsquo;IDT (table des interruptions). L&rsquo;OS traite cette exception par une routine du noyau qui n&rsquo;est généralement pas prévue pour gérer ce cas, donc on aura par défaut droit à un crash du programme ayant appelé RDTSC. Sous Linux, cela se traduit par l&rsquo;envoi d&rsquo;un signal SIGSEGV au processus, causant une segmentation fault.</p>
<h3>IDT hooking</h3>
<p>Pour hooker RDTSC, il faut donc dans un premier temps mettre à 1 le flag TSD (bit 2) de CR4 pour déclencher une #GP. Mais ce que nous voulons, c&rsquo;est appeler notre fonction et non celle du noyau lors de l&rsquo;exception. Il va donc falloir patcher l&rsquo;IDT en remplaçant l&rsquo;adresse du handler 13 par le notre ; autrement dit, faire du IDT hooking.</p>
<p>L&rsquo;IDT recense des descripteurs explicités à la section 5.11 du manuel 3A d&rsquo;Intel. Les descripteurs suivant plus ou moins le même format :</p>
<div id="attachment_690" class="wp-caption aligncenter" style="width: 352px"><a href="http://www.segmentationfault.fr/wp-content/uploads/2009/07/int_desc.PNG"><img class="size-full wp-image-690" title="Interrupt Descriptor" src="http://www.segmentationfault.fr/wp-content/uploads/2009/07/int_desc.PNG" alt="Descripteur d'interruption" width="342" height="124" /></a><p class="wp-caption-text">Descripteur d&#39;interruption</p></div>
<p>Comme d&rsquo;habitude dans la doc Intel, le schéma se lit de bas en haut et de droite à gauche (little endian, quand tu nous tiens&#8230;). A la mode des autres descripteurs propres à l&rsquo;architecture x86, on constate que le champ Offset est découpé en deux parties : poids forts et poids faibles. C&rsquo;est ce champ qui pointe vers le handler à exécuter lors de l&rsquo;exception. Il suffit de remplacer sa valeur par l&rsquo;adresse d&rsquo;une de nos fonctions, et nous pourrons alors détourner le flux d&rsquo;exécution lors d&rsquo;un appel ring 3 à RDTSC.</p>
<h3>Trouver l&rsquo;IDT</h3>
<p>Pour pouvoir faire un hook de l&rsquo;IDT, il faut d&rsquo;abord savoir la trouver. En fait, il est nécessaire de préciser que pour les processeurs multi-coeur, il n&rsquo;y a pas une seule IDT mais plusieurs :  une par cœur. Il est donc en théorie nécessaire de hooker toutes les IDT pour éviter les problèmes. Pour connaître l&rsquo;IDT référencée par un cœur, il suffit d&rsquo;utiliser l&rsquo;instruction SIDT sur ce cœur. Cette instruction est accessible en ring 3 ; <a href="http://nibbles.tuxfamily.org/?p=372">voici un code</a> qui l&rsquo;illustre. Cependant, si vous utilisez Linux dans une machine virtuelle telle que VirtualBox, il se peut que vous rencontriez des problèmes en fonction de vos options de virtualisation. En effet, l&rsquo;instruction SIDT n&rsquo;est pas toujours bien émulée par l&rsquo;hyperviseur et il se peut que la valeur qu&rsquo;elle retourne soit erronée. Préférez-donc la solution suivante si vous tenez à faire vos tests dans une VM.</p>
<p>Même si un procceseur peut avoir plusieurs IDT, Linux n&rsquo;en utilise qu&rsquo;une car chaque cœur référence la même. Celle-ci est définie dans le noyau par le symbole <code>idt_table</code>. Pour connaître son adresse, tentez :</p>
<pre>grep idt_table /proc/kallsyms</pre>
<p>Le premier champ retourné est l&rsquo;addresse de l&rsquo;IDT. Si cela ne vous renvoie rien, il vous faudra à la place utiliser le fichier /boot/Symbol.map, généré à la compilation du noyau. Il se peut que son nom soit quelque peu différent ; par exemple sous Ubuntu il suit le format /boot/System.map-$(uname -r) alors que sous ArchLinux il s&rsquo;appelle /boot/System.map26.</p>
<h3>Conception du handler</h3>
<p>Une bonne conception du nouveau handler d&rsquo;interruption est cruciale pour éviter de rendre instable tout le système. En effet, #GP est utilisée non seulement pour RDTSC mais aussi à chaque fois qu&rsquo;un check de privilèges échoue (pour une bonne ou une mauvaise raison) dans l&rsquo;OS, autrement dit un sacré paquet de fois&#8230; Autant dire qu&rsquo;il est préférable de laisser l&rsquo;OS gérer ces cas là tout seul.</p>
<p>Pour cela, il va falloir filtrer dans un premier temps les #GP dues à RDTSC et celles dues à une autre instruction. Détecter l&rsquo;instruction fautive est facile vu que l&rsquo;EIP a été empilé ; il suffit de le regarder, d&rsquo;examiner ce qu&rsquo;il pointe et de comparer cette valeur à l&rsquo;opcode de RDTSC : 0F 31, soit 0x310F en mot de 16 bits little endian. Si cela ne correspond pas, on saute sur le handler de base de l&rsquo;OS pour ne pas tout crasher.</p>
<p>Ce n&rsquo;est pas tout : les programmes ring 3 de l&rsquo;OS aussi utilisent RDTSC. Si nous leur rendons des valeurs comme 0&#215;11223344, ils risquent d&rsquo;avoir un comportement plutôt imprévisible, surtout s&rsquo;ils s&rsquo;en servent comme base de temps. J&rsquo;ai d&rsquo;ailleurs testé sous Linux ; Cron a segfaulté instantanément et la machine est devenue inutilisable en quelques secondes.</p>
<p>Bref, il faut se débrouiller pour rendre la bonne valeur à ces programmes. La solution est d&rsquo;émuler RDTSC dans le driver, et de transmettre les résultats dans EAX et EDX au ring 3. Mais comment savoir quand retourner les bonnes et valeurs et les fakes ? La solution la plus simple qui m&rsquo;est venue à l&rsquo;esprit est d&rsquo;utiliser le PIDs du processus courant, en supposant que l&rsquo;on connaisse le PID à hooker. Pour transmettre au driver le PID du processus en question, on peut utiliser des IOCTLs, justement prévues pour la communication ring 3 &#8211; ring 0. Une fois que l&rsquo;on a le PID, il suffit de consulter le PID courant et on peut savoir si on doit émuler RDTSC ou forger les valeurs.</p>
<h3>Récupération du PID courant</h3>
<p>Nous avons quasiment tout ce qu&rsquo;il faut pour implémenter cette attaque sous Linux. La seule chose qu&rsquo;il nous manque, c&rsquo;est un moyen dé récupérer le PID du processus courant lorsque l&rsquo;on est dans un handler d&rsquo;interruption. Après lecture en diagonale du chapitre 7 d&rsquo;<a href="http://books.google.fr/books?id=h0lltXyJ8aIC&amp;dq=understanding+linux+kernel&amp;printsec=frontcover&amp;source=bn&amp;hl=fr&amp;ei=RopbSsO8A4z0nQOdwfXdCQ&amp;sa=X&amp;oi=book_result&amp;ct=result&amp;resnum=4">Understanding The Linux Kernel 3rd edition</a>, on constate qu&rsquo;il existe une macro nommée <code>current</code> qui permet de récupérer un pointeur vers le descripteur de processus courant. Après avoir testé cette macro, je me suis rendu compte qu&rsquo;elle ne marche en fait pas dans le contexte d&rsquo;un handler d&rsquo;interruption. Il faut utiliser à la place la fonction <code>current_thread_info()</code> qui marche à tous les coups. A partir de là, récupérer le PID est très simple, via l&rsquo;expression suivante : <code>current_thread_info()-&gt;task-&gt;pid</code>.</p>
<h3>Implémentation 1</h3>
<p>Nous pouvons maintenant implémenter l&rsquo;attaque. Je l&rsquo;ai réalisé sans problèmes particulier sur une Ubuntu 9.04 avec un noyau 2.6.28, sur processeur AMD dualcore. Les sources sont disponibles plus bas ; voici les points principaux.</p>
<pre>//Typedefs
typedef unsigned char u_int8;
typedef unsigned short u_int16;
typedef unsigned int u_int32;
typedef unsigned long long int u_int64;

/**
 * An IDT entry. Cf Intel SDM 3A
 */
typedef struct {
 u_int16 low_offset;
 u_int16 selector;
 u_int8 unused_lo;
 u_int8 segment_type:4;
 u_int8 system_segment_flag:1;
 u_int8 DPL:2;
 u_int8 P:1;
 u_int16 hi_offset;
} __attribute__((packed)) IDTENTRY_ST, *P_IDTENTRY_ST;</pre>
<p>Dans un premier temps, on déclare la structure d&rsquo;un descripteur d&rsquo;interruption. On fera particulièrement attention à bien spécifier <code>__attribute__((packed))</code> pour spécifier au compilateur de ne pas faire de padding entre les champs. La fonction effectuant le hook est ci-après :</p>
<pre>//Interrupt handlers
u_int32 old_int_handler, new_int_handler2;

void HookOneIDT (P_IDTENTRY_ST _p_IDT, u_int32 _interrupt_number,
                 u_int32* _old_address, u_int32 _new_address)
{
 asm("cli\n\t");

 *_old_address =  ((_p_IDT[_interrupt_number].hi_offset &lt;&lt; 16)
                | (_p_IDT[_interrupt_number].low_offset));
 _p_IDT[_interrupt_number].hi_offset = (_new_address &gt;&gt; 16) &amp; 0xFFFF;
 _p_IDT[_interrupt_number].low_offset = (_new_address &amp; 0xFFFF);

 asm("sti\n\t");
}</pre>
<p>Rien de particulier ici, à part une désactivation temporaires des interruptions. D&rsquo;ailleurs, pour être plus rigoureux, il aurait fallu les désactiver sur tous les cœurs, mais comme cette fonction sera appelée avec <code>interrupt_number = 13</code>, qui n&rsquo;est de toutes façon pas masquable, il n&rsquo;y a pas de risque.</p>
<p>Le nouveau handler d&rsquo;interruption est codé à part dans un fichier assembleur. Il s&rsquo;agit en fait d&rsquo;un squelette qui sauvegarde le contexte et appelle une fonction C, pour des raisons de commodité :</p>
<pre>.globl interrupt_handler

//The interrupt handler.
//This function must be naked. Since it's not possible with gcc on x86 platforms, we put it in a separate asm file.
interrupt_handler: 

 //Save registers
 pusha
 pushf

 //Call our hook function and  the parameter
 //Since convention call of my_func_handler is fastcall, parameter has to be in %ecx
 mov %esp, %ecx
 call my_func_handler

 //Check the return value
 cmp $1, %eax

 //If 1, throw the exception away
 je  my_exit

 //Otherwise, restore registers
 popf
 popa

 //Jump to the original handler
 jmpl * old_int_handler

my_exit:

 //Restore registers
 popf
 popa

 //Pop interrupt error code
 add $4, %esp

 //Return from interrupt
 iret</pre>
<p>La fonction appelée, <code>my_func_handler</code>, doit déterminer la nature de l&rsquo;exception et la traiter si besoin en détournant RDTSC. On utilise son code de retour pour savoir si l&rsquo;on repasse la main au handler par défaut de Linux, ou si on se contente de retourner en userland.</p>
<pre>//Opcode for RDTSC : 0F 31 =&gt; 31 OF in little endian
#define RDTSC_OPCODE 0x310F

//Size of RDTSC instruction
#define RDTSC_SIZE   2

/**
 * Interrupt stack structures
 */
typedef struct
{
 u_int32 edi;
 u_int32 esi;
 u_int32 ebp;
 u_int32 esp;
 u_int32 ebx;
 u_int32 edx;
 u_int32 ecx;
 u_int32 eax;
} PUSHA_ST, *P_PUSHA_ST;

typedef struct
{
 u_int32 error_code;  // !! Check Intel Manuals to see if the error code is present or not
 u_int32 eip;
 u_int32 cs;
 u_int32 eflags;
 u_int32 esp;
 u_int32 sp;
} INT_STACK_HARD_ST, P_INT_STACK_HARD_ST;

typedef struct
{
 u_int32              eflags;

 PUSHA_ST             pusha_st;
 INT_STACK_HARD_ST    int_stack_hard_st;

} MY_INT_STACK_ST, *P_MY_INT_STACK_ST;

/**
 * Return current PID
 */
unsigned int GetCurrentPID (void)
{
 // !!! The 'current' macro doesn't work in interrupt context !
 // !!! We have to use current_thread_info()-&gt;task instead
 return current_thread_info()-&gt;task-&gt;pid;
}

/**
 * Function called by the interrupt handler.
 *  !! WARNING !! Don't call printk() inside, or the kernel will freeze !
 *
 * @param stack pointer to the stack
 * @return 0 if this is a normal #GP exception,
 * 1 if it is due to our RDTSC hook
 */
u_int32  __attribute__((__fastcall__))
         my_func_handler (P_MY_INT_STACK_ST stack)
{
 //nb_interrupts++;+
 asm volatile("lock incl nb_interrupts\n\t");

 //Detect if the instruction that triggered the exception is RDTSC
 if(* (u_int16*) stack-&gt;int_stack_hard_st.eip == (u_int16) RDTSC_OPCODE)
 {
 //Check who is executing RDTSC
 if(GetCurrentPID() == pid_to_hook)
 {
 //Change EAX and EDX with magic values
 stack-&gt;pusha_st.eax = 0x11223344;
 stack-&gt;pusha_st.edx = 0x55667788;
 }
 else
 {
 //Perform a normal call to RDTSC
 RDTSC_ST rdtsc;
 RDTSC(&amp;rdtsc);

 stack-&gt;pusha_st.eax = rdtsc.eax;
 stack-&gt;pusha_st.edx = rdtsc.edx;
 }

 //Increment EIP
 stack-&gt;int_stack_hard_st.eip += RDTSC_SIZE;

 return 1;
 }
 else
 {
 return 0;
 }

}</pre>
<p>Il y a plusieurs détails qui ont leur importance. D&rsquo;une part,on définit des structures correspondant à l&rsquo;état de la pile lors de l&rsquo;appel à cette fonction. Cela inclut les registres généraux pushés par PUSHA ainsi que les valeurs pushés automatiquement par le processeur. Il faut faire attention à bien inverser leur ordre relativement aux specifications d&rsquo;Intel, vu que la pile croît des addresses hautes vers les basses. On récupère l&rsquo;EIP empilé, on déréférence ce pointeur et on compare le mot de 16 bits avec l&rsquo;opcode de RDTSC renversé (vu qu&rsquo;il se trouve en mémoire, donc en little-endian). On émule RDTSC su besoin, et on n&rsquo;oublie pas d&rsquo;incrémenter EIP afin de sauter par dessus l&rsquo;instruction lors du retour. On notera que le debug de cette fonction n&rsquo;est pas trivial, car il est impossible d&rsquo;utiliser des fonctions comme <code>printk()</code> à l&rsquo;intérieur.</p>
<p>Voici désormais la partie relative aux IOCTLs. Je n&rsquo;ai pas détaillé cette partie précédemment car elle fait plutôt partie d&rsquo;un choix d&rsquo;implémentation.</p>
<pre>#include &lt;linux/ioctl.h&gt;

//The device name in /proc/devices
#define DEVICE_NAME        "rdtsc_exploit"

//The name of the device file in /dev
#define DEVICE_FILE_NAME   "/dev/rdtsc_exploit"

//IOCTL command codes
#define IOCTL_SET_PID    _IOWR(0, 0, unsigned int)

//Device major and minor numbers
static dev_t g_device_num;

//Count the number of hooked interrupts
extern volatile unsigned int nb_interrupts;

//The file_operation structure, to link the device
//to the appropriate handlers
static struct file_operations g_fops = {
 .owner   = THIS_MODULE,
 .ioctl   = my_ioctl,
};

//Char device structure
static struct cdev g_device;</pre>
<p>Sous Linux, pour pouvoir communiquer avec un module en utilisant des IOCTLs, il faut créer un périphérique virtuel en mode caractère (char device) et lui assigner un handler l&rsquo;ioctl. Ce device possèdera un numéro majeur dynamiquement alloué par le noyau. Pour le numéro mineur, nous choisissons simplement 0. Une fois ces ressources allouées, nous enregistrons le device ce qui a pour effet de le faire apparaître dans /proc/devices. Tout ce procédé est fort bien décrit aux chapitres 3 et 6 de <a href="http://lwn.net/Kernel/LDD3/">Linux Device Drivers, 3rd edition</a>, livre libre que je vous conseille vivement.</p>
<pre>/**
 * Create the device
 */
int create_device (void)
{
 //Allocate the device major and minor
 if(alloc_chrdev_region(&amp;g_device_num, 0, 1, DEVICE_NAME))
 {
 printk(KERN_INFO "ERROR: alloc_chrdev_region FAILED\n");
 return -1;
 }

 //Initialise the device
 cdev_init(&amp;g_device, &amp;g_fops);

 //Fill in some fields (optional)
 g_device.owner = THIS_MODULE;
 g_device.ops = &amp;g_fops;

 //Register the device into the kernel
 if(cdev_add(&amp;g_device, g_device_num, 1))
 {
 printk(KERN_INFO "ERROR: cdev_add FAILED\n");
 return -1;
 }

 printk(KERN_INFO "Device registrated successfully - name = %s, "
                  "major = %d, minor = %d\n", DEVICE_NAME,
                  MAJOR(g_device_num), MINOR(g_device_num));

 return 0;
}

/**
 * Delete the device
 */
void delete_device (void)
{
 //Unregister the device
 cdev_del(&amp;g_device);

 //Unregister the device number
 unregister_chrdev_region(g_device_num, 1);
}</pre>
<p>Ces deux fonctions réalisent la création et la suppression du device.</p>
<p>Pour manipuler le flag TSD de CR4, on cree les fonctions suivantes :</p>
<pre>//Flag of CR4 that disable RDTSC in userland
#define FLAG_DISABLE_USER_RDTSC 0x4

/**
 * Get CR4 value
 */
u_int32 GetCR4 (void)
{
 u_int32 res = 0;

 asm volatile (
 "push %%eax\t\n"
 "mov %%cr4, %%eax\t\n"
 "mov %%eax, %0\t\n"
 "pop %%eax\t\n"
 : "=m"(res));

 return res;
}

/**
 * Set CR4 value
 */
void SetCR4 (u_int32 _new_cr4)
{
 asm volatile(
 "push %%eax\t\n"
 "mov %0, %%eax\t\n"
 "mov %%eax, %%cr4\t\n"
 "pop %%eax\t\n"
 : : "m" (_new_cr4));
}

/**
 * Enable userland calls to RDTSC
 */
void EnableUserRDTSC (void)
{
 SetCR4(GetCR4() &amp; ~FLAG_DISABLE_USER_RDTSC);
}

/**
 * Disable userland calls to RDTSC
 */
void DisableUserRDTSC (void)
{
 SetCR4(GetCR4() | FLAG_DISABLE_USER_RDTSC);
}</pre>
<p>On notera au passage la syntaxe assez inhabituelle de l&rsquo;assembleur inline de GCC, notemment les doubles % nécessaires puisque l&rsquo;on utilise des références (%0), ainsi que les \n\t en fin de ligne. Et bien entendu, les arguments inversés par rapport à la syntaxe officielle d&rsquo;Intel.</p>
<p>Lors du chargement du driver, il suffira de hooker l&rsquo;IDT et de positionner le flag CR4.TSD. Cependant, cette dernière opération doit être faite sur tous les coeurs. On utilisera donc la macro <code>on_each_cpu()</code>.</p>
<pre>//Hook the General Protection Fault handler (0x0D)
#define INTERRUPT_VECTOR_TO_HOOK 0x0D

#include &lt;linux/module.h&gt;  /* Needed by all modules */
#include &lt;linux/kernel.h&gt;  /* Needed for KERN_ALERT */
#include &lt;linux/init.h&gt;     // Needed for the macros

#include "../include/defines.h"
#include "hook.h"
#include "device.h"

static int module_load(void)
{
 Hook();
 create_device();

 //Must return 0, otherwise the module is not loaded
 return 0;
}

static void module_unload(void)
{
 delete_device();
 UnHook();
}  

module_init(module_load);
module_exit(module_unload);

/**
 * Hook
 */
void Hook ()
{
 //Get the IDT address (all CPUS use the same)
 P_IDTENTRY_ST pIDT = GetIDTSoft();

 printk(KERN_INFO "interrupt_handler = %08x\n", (u_int32) interrupt_handler);

 //Hook interrupt handler
 HookOneIDT(pIDT, INTERRUPT_VECTOR_TO_HOOK,
            &amp;old_int_handler, (u_int32) interrupt_handler);

 //Hook RDTSC
 on_each_cpu(DisableUserRDTSC, 0, 0);
}

/**
 * Unhook
 */
void UnHook ()
{
 //Unhook RDTSC
 on_each_cpu(EnableUserRDTSC, 0, 0);

 //Unhook interrupt handler
 HookOneIDT(GetIDTSoft(), INTERRUPT_VECTOR_TO_HOOK,
            &amp;new_int_handler2, old_int_handler);
}</pre>
<p>Dans mon prototype, je récupère l&rsquo;adresse de l&rsquo;IDT en userland dans le Makefile&#8230;</p>
<pre>IDT_ADDRESS = "0x`grep idt_table /boot/System.map-2.6.28-11-generic
               | cut -d ' ' -f 1`"</pre>
<p>&#8230; que je passe en paramètre à GCC lors de la compilation avec le flag -D. Le module la récupère comme une constante pré-processeur :</p>
<pre>/**
 * Get a pointer to the IDT - the soft way.
 * Works perfectly in VMs, but we either have to hardcode the IDT offset,
 * or read it from userland ('grep idt_table /proc/kallsyms'
 * or 'grep idt_table /boot/System.map').
 */
P_IDTENTRY_ST GetIDTSoft (void)
{
 P_IDTENTRY_ST pIDT = 0;

 pIDT = (P_IDTENTRY_ST) IDT_ADDRESS;

 return pIDT;
}</pre>
<p>En userland, il faudra transmettre le PID à hooker au device, ce qui se fait par le code suivant :</p>
<pre>#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;unistd.h&gt;

#include &lt;fcntl.h&gt;
#include &lt;sys/ioctl.h&gt;

#include "defines.h"

int main(int ac, char **av)
{

 //int i;
 int fd;
 int pid_to_hook;

 if(ac != 2)
 {
 printf("Usage: set_pid pid\n");
 printf("Set the pid to hook.\n\n");
 exit(0);
 }

 pid_to_hook = atoi(av[1]);

 if(pid_to_hook &lt;= 0)
 {
 fprintf(stderr, "Error, pid must be &gt; 0.\n");
 exit(1);
 }

 //Open the device in order to communicate with the driver
 fd = open(DEVICE_FILE_NAME, O_RDONLY);

 if(fd == -1)
 {
 printf("Error: %s does not exist!\n", DEVICE_FILE_NAME);
 exit(1);
 }

 //Send IOCTLs to the driver to set the pid do hook
 if(ioctl(fd, IOCTL_SET_PID, pid_to_hook))
 {
 fprintf(stderr, "Error setting the pid.\n");
 }
 else
 {
 printf("pid set successfully.\n");
 }

 //Close the device
 close(fd);

}</pre>
<p>Enfin, la routine de traitement de l&rsquo;IOCTL qui sert à récupérer le PID dans le module est relativement simple :</p>
<pre>/**
 * IOCTL handler
 */
int my_ioctl (struct inode * _inode, struct file * _file,
              unsigned int _ioctl_num, unsigned long _ioctl_param)
{
 struct task_struct *task;

 switch(_ioctl_num)
 {
 //Set the PID
 case (IOCTL_SET_PID):

 pid_to_hook = (unsigned int) _ioctl_param;

 break;

 default:
 printk(KERN_INFO "rdtsc_exploit: ERROR: Unsupported ioctl code: "
                  "%08x.\n", _ioctl_num);
 }
 return 0;
}</pre>
<h3>Test</h3>
<p>Après avoir compilé le tout, on charge le module :</p>
<pre># insmod module/rootkit.ko
# grep rdtsc_exploit /proc/devices
250 rdtsc_exploit
# mknod /dev/rdtsc_exploit c 250 0</pre>
<p>On lance le programme exécutant RDTSC dans un shell à part :</p>
<pre>$ exe/rdtsc/rdtsc
Press &lt;Enter&gt; to call rdtsc. Press q to quit.

RDTSC result (edx : eax) = (0000126d : 8c1cc9a2)

RDTSC result (edx : eax) = (0000126d : a38e75be)</pre>
<p>Puis on envoie son PID au module avec :</p>
<pre># exe/set_pid/set_pid $(pidof rdtsc)
pid set successfully.</pre>
<p>Et on revient au terminal précédent, en constatant que le hook fonctionne bien :</p>
<pre>RDTSC result (edx : eax) = (55667788 : 11223344)

RDTSC result (edx : eax) = (55667788 : 11223344)

RDTSC result (edx : eax) = (55667788 : 11223344)</pre>
<p>On n&rsquo;oubliera pas de décharger le module avec :</p>
<pre># rmmod rootkit
# rm /dev/rdtsc_exploit</pre>
<h3>Problème avec ArchLinux</h3>
<p>En testant l&rsquo;implémentation précédente avec deux distributions ArchLinux de noyaux 2.6.29 et 2.6.30, j&rsquo;ai constaté qu&rsquo;ell ne marchait tout simplement pas. En faisant plusieurs tests, je constate que le handler de #GP est bien hooké, mais RDTSC ne l&rsquo;est pas du tout car le programme de test affiche toujours des valeurs normales. J&rsquo;affiche la valeur de CR4.TSD à plusieurs reprises, et je vois que de temps en temps, il repasse à 0, ce qui expliquerait pourquoi RDTSC n&rsquo;est pas détournée.</p>
<p>Après plusieurs recherches, je tombe sur <a href="http://blog.cr0.org/2009/05/time-stamp-counter-disabling-oddities.html">ce blog</a>, qui pointe du doigt quelques bizarreries du noyau Linux concernant justement le flag TSD. Apparemment, il serait possible de l&rsquo;activer ou non pour certains processus seulement. Il s&rsquo;agit du Thread Information Flag TIF_NOTSC définit dans le fichier arch/x86/include/asm/thread_info.h du noyau. Ce flag est plus ou moins l&rsquo;équivalent du flag TSD, mais dans le contexte de chaque processus. Il est possible de le définir avec l&rsquo;appel système <a href="http://www.kernel.org/doc/man-pages/online/pages/man2/prctl.2.html">prctl</a> en utilisant l&rsquo;option PR_SET_TSC. La valeur PR_TSC_ENABLE revient à positionner TSD = 0, tandis que PR_TSC_SIGSEGV est équivalent à TSD = 1.</p>
<p>Ces flags existent déjà dans les noyaux 2.6.28 d&rsquo;Ubuntu 9.04 ; je n&rsquo;ai pas encore bien saisi pourquoi ceuxi-ci sont effectivement appliqués sur ArchLinux. Le blog cité précédemment parle de l&rsquo;option de configuration CONFIG_SECCOMP du noyau, présente sur ArchLinux, mais visiblement désactivée ia le flag TIF_SECCOMP qui vaut 0 pour tous les processus. Je vais continuer mes recherches de ce côté&#8230; Si toutefois vous avez des explications, je suis preveur <img src='http://www.segmentationfault.fr/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p>
<h3>Implémentation 2</h3>
<p>En attendant, il reste tout de même effectuer le hook de RDTSC. Il suffit de positionner le flag TIF_NOTSC du processus en question à PR_TSC_SIGSEGV. Cela peut se faire en appelant prctl, mais cette technique n&rsquo;est pas vraiment convenable car un hook se doit d&rsquo;être extérieur au processus. La technique consiste donc à émuler le fonctionnement de cet appel système au sein de notre module. Il nous suffit de parcourir la liste chainée des processus, d&rsquo;isoler celui qui a le bon PID, et à positionner son flag. Cela revient à modifier la fonction <code>my_ioctl()</code> comme ceci :</p>
<pre>/**
 * IOCTL handler
 */
int my_ioctl (struct inode * _inode, struct file * _file,
              unsigned int _ioctl_num, unsigned long _ioctl_param)
{
   struct task_struct *task;

   switch(_ioctl_num)
   {
      //Set the PID
      case (IOCTL_SET_PID):

         pid_to_hook = (unsigned int) _ioctl_param;
         printk(KERN_INFO "rdtsc_exploit: pid_to_hook = "
                          "%d.\n", pid_to_hook);

         for_each_process(task) {
            if(task-&gt;pid == pid_to_hook){
               test_and_set_ti_thread_flag(task_thread_info(task), TIF_NOTSC);
               printk("TIF_NOTSC set for process %d\n", task-&gt;pid);
            }
         }

      break;

      default:
         printk(KERN_INFO "rdtsc_exploit: ERROR: Unsupported ioctl code: "
                          "%08x.\n", _ioctl_num);
   }
   return 0;
}</pre>
<p>La macro <code>for_each_process()</code> définie dans linux/sched.h permet d&rsquo;itérer très simplement sur les threads du système. On utilise la fonction <code>test_and_set_ti_thread_flag()</code> afin de positionner le flag TIF_NOTSC du thread en question. On notera qu&rsquo;il n&rsquo;y a même plus besoin de modifier à la main CR4 à l&rsquo;initialisation.</p>
<h3>Sources</h3>
<p><a href="http://www.segmentationfault.fr/wp-content/uploads/2009/07/rdtsc_exploit.tar.gz">Téléchargez les sources</a></p>
<p>Les sources incluent l&rsquo;implémentation 2, sachant que celle-ci fonctionne aussi bien sur les deux distributions que j&rsquo;ai testées (Ubuntu et ArchLinux). Les lignes spécifiques à la 1ère implémentation sont commentées, donc vous pouvez toujours jouer avec et voir le résultat que vous obtenez.</p>
<p>Pour compiler, invoquez simplement <code>make</code> à la racine de rdtsc_exploit. Si jamais cela ne compile pas, éditez le fichier module/Makefile, et indiquez le bon chemin vers votre fichier /boot/System.map. Vérifiez également que le fichier module/handler.S a bien un S majuscule concernant son extension.</p>
<p>Les fichiers fournis sont organisés comme ceci :</p>
<ul>
<li>module/ contient les sources du module</li>
<li>exe/ contient deux sources d&rsquo;exécutables :
<ul>
<li>rdtsc : programme de test exécutant RDTSC à chaque appui sur une touche. Il contient aussi un fichier de test du noyau,  disable-tsc-test.c, que j&rsquo;ai jugé intéressant de garder pour des tests. A compiler séparément.</li>
<li>set_pid : programme prenant en paramètre le PID de rdtsc et l&rsquo;envoyant au module par ioctl</li>
</ul>
</li>
<li>scripts/ contient trois scripts permettant d&rsquo;automatiser le chargement du module et la création du device. load_hook.sh et unload_hook.sh appellent en réalité load.sh, capable de charger/décharger un module et créer/détruire son device.</li>
</ul>
<h3>Applications</h3>
<p>Pour terminer, voici quelques possibilités offertes par le hook de RDTSC :</p>
<ul>
<li><strong>Empoisonnement des générateurs de nombres pseudo-aléatoires</strong> : Certaines applications utilisent RDTSC comme source d&rsquo;aléa, pour générer des valeurs pseudo-aléatoires qui peuvent par exemple être utilisées pour la génération de clé de chiffrement. En forçant à RDTSC à renvoyer des valeurs bien précise, on peut injecter des valeurs bien précises dans l&rsquo;algorithme de génération et pouvoir prédire plus facilement son résultat.</li>
<li><strong>Anti-anti-debuging</strong> : Comme dit au premier paragraphe, une technique d&rsquo;anti-debug consiste à utiliser RDTSC pour estimer le temps passé entre deux instructions et le comparer à une valeur seuil. Une technique d&rsquo;anti-anti-debug peut donc être de hooker RDTSC et de retourner des valeurs plausibles à l&rsquo;application, en masquant le fait que celle-ci est en train de se faire déboguer. C&rsquo;est précisément ce que fait le plugin <a href="http://www.openrce.org/downloads/details/241/Olly_Advanced">Olly Advanced</a> d&rsquo;OllyDbg.</li>
<li><strong>Communication offusquée entre une application et un driver</strong> : Puisqu&rsquo;avec cette technique RDTSC est exécutée en ring 3 et provoque une exception #GP en ring 0, c&rsquo;est un moyen de donner la main à un driver afin qu&rsquo;il effectue des opérations &laquo;&nbsp;ni vu ni connu&nbsp;&raquo;, dans le sens ou il n&rsquo;y a aucun appel explicite vers fonction noyau dans l&rsquo;application ring 3.</li>
</ul>
<h3>Conclusion</h3>
<p>Cette technique n&rsquo;est pas nouvelle, mais encore assez peu connue (enfin sans doute pas des reversers :p). Cependant, elle peut se révéler très intéressantes dans de multiples occasions. Si je devais donner un conseil, ce serait d&rsquo;éviter de l&rsquo;utiliser en ring 3, pour deux raisons principales de sécurité :</p>
<ul>
<li>Il existe des générateurs aléatoires reconnus comme fiables, il est donc préférable de les utiliser plutôt que de se faire son propre algorithme.</li>
<li>L&rsquo;OS fournit généralement des appels systèmes permettant d&rsquo;appeler RDTSC en ring 0 et de retourner sa valeur (cf <code>NtQueryPerformanceCounter()</code> sous Windows). Comme l&rsquo;appel est en ring 0, la méthode de hook décrite précédemment ne marche plus.</li>
</ul>
<h3>Références</h3>
<ul>
<li><a href="https://www.blackhat.com/presentations/bh-usa-07/Yason/Whitepaper/bh-usa-07-yason-WP.pdf">The Art of Unpacking</a>, Marc Vincent Yason, BlackHat 2007</li>
<li><a href="http://www.intel.com/products/processor/manuals/">Intel Software Devloper&rsquo;s Manuals</a> 2B, 3A</li>
<li><a href="http://books.google.fr/books?id=h0lltXyJ8aIC&amp;dq=understanding+linux+kernel&amp;printsec=frontcover&amp;source=bn&amp;hl=fr&amp;ei=RopbSsO8A4z0nQOdwfXdCQ&amp;sa=X&amp;oi=book_result&amp;ct=result&amp;resnum=4">Understanding the Linux kernel, 3rd edition</a>, <span>Daniel Pierre Bovet, Marco Cesati, </span>O&rsquo;Reilly</li>
<li><a href="http://nibbles.tuxfamily.org/?p=372">Nibbles &#8211; SMP : IDT et GDT</a>, j0rn</li>
<li><a href="http://lwn.net/Kernel/LDD3/">Linux Device Drivers, 3rd edition</a>, Jonathan Corbet, Alessandro Rubini, Greg Kroah-Hartman, O&rsquo;Reilly</li>
<li><a href="http://blog.cr0.org/2009/05/time-stamp-counter-disabling-oddities.html">CR0&prime;s blog : Time-stamp counter disabling oddities in the Linux kernel</a></li>
<li><a href="http://www.kernel.org/doc/man-pages/online/pages/man2/prctl.2.html">Man prctl</a></li>
</ul>
<div id="_mcePaste" style="overflow: hidden; position: absolute; left: -10000px; top: 11920px; width: 1px; height: 1px;">
<pre><strong><strong>PR_SET_TSC</strong></strong></pre>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.segmentationfault.fr/securite-informatique/rdtsc-hooking-linux/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Nuit Du Hack 2009 : Et les vainqueurs sont&#8230;</title>
		<link>http://www.segmentationfault.fr/securite-informatique/bilan-nuit-du-hack-2009/</link>
		<comments>http://www.segmentationfault.fr/securite-informatique/bilan-nuit-du-hack-2009/#comments</comments>
		<pubDate>Sun, 14 Jun 2009 20:17:00 +0000</pubDate>
		<dc:creator>Emilien Girault</dc:creator>
				<category><![CDATA[Nuit du hack]]></category>
		<category><![CDATA[Publications]]></category>
		<category><![CDATA[Reverse Engineering]]></category>
		<category><![CDATA[Sécurité informatique]]></category>
		<category><![CDATA[hacking]]></category>
		<category><![CDATA[pentest]]></category>
		<category><![CDATA[XeeK]]></category>

		<guid isPermaLink="false">http://www.segmentationfault.fr/?p=655</guid>
		<description><![CDATA[Tant attendue, la NDH 2009 s&#8217;est terminée ce matin même. La péniche sur laquelle se déroulait l&#8217;événement battait son plein ; nous étions quasiment 200 à bord. Pour la première fois, le challenge était un Capture The Flag  au cours duquel se sont affrontés une demi douzaine d&#8217;équipes. Mais cette année, la team de Ghosts [...]]]></description>
			<content:encoded><![CDATA[<p>Tant attendue, la NDH 2009 s&rsquo;est terminée ce matin même. La péniche sur laquelle se déroulait l&rsquo;événement battait son plein ; nous étions quasiment 200 à bord. Pour la première fois, le challenge était un Capture The Flag  au cours duquel se sont affrontés une demi douzaine d&rsquo;équipes. Mais cette année, la team de Ghosts In The Stack n&rsquo;était pas au complet car il manquait Heurs, contraint de ne pas participer au challenge vu qu&rsquo;il fait désormais partie du staff. Ma team, répondant au nom de Trollkore (un trip IRC&#8230;) était donc composée d&rsquo;Ivanlef0u, sh4ka, Pierz et Kal0n. Et c&rsquo;est notre équipe qui a remporté le challenge ! Voici, rien que pour vous, un petit résumé de cette super nuit organisée par <a href="http://www.sysdream.com">Sysdream</a>. [EDIT 15/16/09 : slides et sources mis en ligne]<span id="more-655"></span></p>
<h3>Conférences</h3>
<p>Le programme était aussi riche qu&rsquo;intense : une douzaine de conférences se déroulant sur deux plateformes ; il y avait donc toujours deux confs en simultané. L&rsquo;inconvénient était toutefois qu&rsquo;on ne pouvait assister qu&rsquo;à la moitié des confs&#8230; Pour ma part, j&rsquo;ai alterné entre les deux plateformes, et j&rsquo;ai en plus du finaliser quelques slides donc je n&rsquo;ai pas pu en profiter pleinement. Au final, voila ce à quoi j&rsquo;ai assisté :</p>
<ul>
<li><strong>SCOW &#8211; ShellCoding On Windows</strong> : Heurs présente son nouvel outil permettant de générer un shellcode générique sous Wndows à partir d&rsquo;un simple programme C. Un outil permettant de gagner un temps fou lors de la conception d&rsquo;un exploit, avec en prime une polymorphisation du shellcode en question.</li>
<li><strong>GoRing0 </strong>: Présentée par moi-même. Cette conférence se veut accessible à tous ceux qui s&rsquo;intéressent de près ou de loin au noyau et au fonctionnement des processeurs x86, en particulier le système de privilèges (ring). J&rsquo;y présente dans un premier temps toutes les bases nécessaire pour comprendre le coeur de la conférence : un rootkit que j&rsquo;ai développé et qui permet de passer un thread en ring 0, le contexte étant préservé.</li>
<li><strong>Drive by Pharming</strong> : Abc528 présente une faille XSRF des routeurs de type box (Alicebox, Livebox&#8230;) permettant de modifier leur configuration depuis une page HTML hébergée sur un site quelconque.</li>
<li><strong>XeeK </strong>: Ma deuxième conf de la soirée. Je présente XeeK, un projet dont j&rsquo;ai déjà parlé <a href="http://www.segmentationfault.fr/projets/xeek-framework-exploitation-xss/">ici</a>, mais que je n&rsquo;ai pas encore eu le temps de finir. Il s&rsquo;agit d&rsquo;un framework visant à exploiter les failles XSS très rapidement et simplement.</li>
<li><strong>Lockpicking </strong>: Cocolitos et Mr Jack nous démontrent qu&rsquo;aucun verrou n&rsquo;est vraiment sûre, en crochetant différents types de serrures, les unes à la suite des autres. On y apprend entre autres qu&rsquo;on peut crocheter certaines serrures avec un bout d&rsquo;essuie glace, et ouvrir un cadenas avec une canette. Même certaines serrures réputées haute sécurité y passent.</li>
</ul>
<p>Dommage, j&rsquo;ai loupé la conférences de Virtualabs sur les framework Web next gen, qui pourraient fortement m&rsquo;intéresser pour poursuivre XeeK.</p>
<p>Sinon, si je devais donner mon opinion sur les 3 confs que j&rsquo;ai vues, je dirai qu&rsquo;elles étaient à la hauteur de mes attentes et qu&rsquo;elles valaient vraiment le coup d&rsquo;oeil, sauf une : le Drive By Pharming. Soyons clairs : je respecte tous les conférenciers ainsi que les présentations qu&rsquo;ils ont données. Mais je pense que cette conférence, bien que s&rsquo;adressant à des débutants, manquait de préparation, de contenu (elle a duré 10 min) et contenait des erreurs assez flagrantes. Je reste enthousiaste à l&rsquo;idée d&rsquo;accueillir des confs de tous les niveaux, mais je pense toutefois que les conférenciers ne devraient pas hésiter à approfondir un peu plus leurs sujets. Enfin, pour ce qui est de la conférence sur le lockpicking, bien que je n&rsquo;ai aucune expérience en la matière, j&rsquo;ai vraiment adoré.</p>
<h3>Slides</h3>
<p>Voici les slides de mes conférences ainsi que les sources/binaires que je publie :</p>
<ul>
<li><strong>GoRing0 </strong>: <a href="http://www.segmentationfault.fr/wp-content/uploads/2009/06/goring0.pdf">Slides </a>- <a href="http://www.segmentationfault.fr/wp-content/uploads/2009/06/goring0-bin.zip">Binaires </a>- <a href="http://www.segmentationfault.fr/wp-content/uploads/2009/06/goring0-src.zip">Sources</a></li>
<li><strong>XeeK </strong>: <a href="http://www.segmentationfault.fr/wp-content/uploads/2009/06/xeek.pdf">Slides</a></li>
</ul>
<p>Pour les autres, allez sur le <a href="http://www.nuitduhack.com">site officiel</a> ou contacter directement les conférenciers.</p>
<h3>Challenge</h3>
<p>Grosse nouveauté de cette année : le challenge principal est un Capture The Flag. Le principe est simple : chaque équipe possède quelques serveurs, leur but étant de les protéger et d&rsquo;attaquer ceux des autres. En gros :</p>
<ul>
<li>Règle n°1 : pas d&rsquo;attaques physiques.</li>
<li>Règle n°2 : pas d&rsquo;attaques sur le serveur du staff.</li>
<li>Règle n°3 : tout le reste est permis. Même  le déni de service.</li>
</ul>
<p>Pour pimenter l&rsquo;affaire, aucune information n&rsquo;est donnée au préalable, pas même les IP de nos propres machines. Pas de DHCP. Il nous faut alors sniffer le traffic pour nous apercevoir qu&rsquo;une machine emmet en broadcast. Nous nous attribuons donc des IP statiques sur la même plage, et configurons la machine qui broadcast comme passerelle. A partir de là, nous découvrons le serveur de monitoring qui contient les résultats en temps réel su challenge avec le classement des équipes, ainsi que la liste de toutes les machines. Autant dire que Nmap a bien tourné&#8230;</p>
<p>On nous fait parvenir les logins/pass de notre machine Windows, mais pas ceux de celle sous Linux. Prétexte:  ils sont facile à trouver. Je m&rsquo;acharne donc à bruteforcer avec Hydra (en l&rsquo;ayant recompilé au passage avec le support pour SSH), mais rien n&rsquo;y fait. Pierz se penche sur Windows, fait tourner Metasploit, et découvre que les machines sont vulnérables au MS08_067. En quelques secondes, il roote une machine adverse et récupère les hashs à valider. Le score décolle enfin ! Décidé à faire baisser le score des autres équipes, j&rsquo;exploite la vuln à mon tour et en profite supprimer le contenu de c:\Windows\system32 ainsi que boot.ini et autoexec.bat, puis je lance un reboot. Cependant, je n&rsquo;avais pas prévu que Windows restaurerai ces 2 fichiers et que la machine booterait toujours. Dommage&#8230;</p>
<p>Pendant ce temps, sh4ka et Ivan s&rsquo;acharnent sur notre Windows en remote desktop. Ivan se fait plaisir sur les crackmes fournis et les reverse rapidement. Kal0n est quant à lui sur un exploit PhpMyAdmin. Avec Sh4ka, je me penche sur le Web. Cependant, il y a un imprévu : le challenge Web prévu est inaccessible car mal configuré. Nous allons alors sur le serveur commun que HZV a laissé pour que même les non participants puissent s&rsquo;entraîner. Nous trouvons rapidement une include locale, une injection SQL, une faille par authentification faible via cookies et une XSS qui n&rsquo;a d&rsquo;ailleurs pas été validé (non prévue à la base). Pendant ce temps, Ivan se penche sur un crackme en kernel, qui lui donne du fil à retordre mais qui fini par tomber.</p>
<p>Aux environs de 5h, on finit par nous donner les accès Linux. Dépités, nous constatons que le login/pass n&rsquo;était en effet pas bien dur à trouver (freeman:team2). En supposant que la combinaison soit similaire sur les autres machines, nous parvenons à nous connecter chez les autres équipes. Mais nous voyons que tout a été chrooté dans tous les sens, et qu&rsquo;au final n&rsquo;avons accès qu&rsquo;à cat, ls, cs, mv, mkdir et python. Nous découvrons plusieurs binaires suid root, dont un vulnérable à un buffer overflow. L&rsquo;ASLR étant activé, l&rsquo;exploitation via  ret onto ret est toujours faisable mais comme nous n&rsquo;avons pas gdb sur la machine distante, et qu&rsquo;il commence à se faire tard (ou tôt, question de point de vue), nous préférons nous arrêter là. En plus, nous sommes une des seules équipes restantes&#8230;</p>
<h3>Remise des prix</h3>
<p>Vers 6h, Crashfr annonce les résultats. Nous sommes premiers ! Jamais nous n&rsquo;aurions pensé gagner, car nous nous attendions à affronter Dvrasp, Fozzy et Artyc&#8230; Mais en fait, il étaient trop occupés au bar <img src='http://www.segmentationfault.fr/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Crashfr remet les prix aux équipes : des certifications CEH pour les 1ers, et des livres pour les deuxièmes et troisièmes. Sans oublier bien sûr les super trophées en verres, réalisés pour l&rsquo;occasion. Pour ma part, comme je serai bientôt consultant chez Sysdream, je pense plutôt convertir ce CEH en LPT (Licensed Penetration Tester), une autre certification d&rsquo;EC-Council. En tout cas, si j&rsquo;ai particupé à cette nuit, c&rsquo;était uniquement pour le fun. Comme d&rsquo;habitude, la NDH est de mieux en mieux, et son ampleur augmente au fil du temps. A quand une NDH rivalisant avec le Black Hat et le Defcon ? En plus, c&rsquo;était ma dernière NDH en tant que challenger, vu que l&rsquo;année prochaine je ferai partie du staff et je pourrai à mon tour goûter aux joies de voir tout le monde s&rsquo;arracher les cheveux sur un challenge dont je suis l&rsquo;auteur <img src='http://www.segmentationfault.fr/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>See you next year !</p>
]]></content:encoded>
			<wfw:commentRss>http://www.segmentationfault.fr/securite-informatique/bilan-nuit-du-hack-2009/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Tunnez votre BSOD (Blue Screen Of Death)</title>
		<link>http://www.segmentationfault.fr/securite-informatique/tunnez-votre-bsod-blue-screen-of-death/</link>
		<comments>http://www.segmentationfault.fr/securite-informatique/tunnez-votre-bsod-blue-screen-of-death/#comments</comments>
		<pubDate>Thu, 30 Apr 2009 18:58:35 +0000</pubDate>
		<dc:creator>Emilien Girault</dc:creator>
				<category><![CDATA[Reverse Engineering]]></category>
		<category><![CDATA[Sécurité informatique]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[ring 0]]></category>

		<guid isPermaLink="false">http://www.segmentationfault.fr/?p=631</guid>
		<description><![CDATA[Tous les développeurs de drivers et les reversers kernel vous le diront : quand on touche au noyau Windows d&#8217;un peu trop près, on a le droit à un écran bleu de la mort, ou BSOD (Blue Screen Of Death). C&#8217;est justement parce que je me suis pris un tas de BSOD que j&#8217;ai commencé [...]]]></description>
			<content:encoded><![CDATA[<p>Tous les développeurs de drivers et les reversers kernel vous le diront : quand on touche au noyau Windows d&rsquo;un peu trop près, on a le droit à un écran bleu de la mort, ou BSOD (Blue Screen Of Death). C&rsquo;est justement parce que je me suis pris un tas de BSOD que j&rsquo;ai commencé à en avoir marre de voir des écrans bleus partout et à me poser des questions existentielles du genre : pourquoi l&rsquo;écran bleu est-il bleu ? Est-ce possible de changer cela ? Oui, et je vais montrer dans cet article comment faire en ne modifiant qu&rsquo;un octet en mémoire kernel. Matériel requis : une deuxième machine (une VM fait très bien l&rsquo;affaire), Windbg, IDA PRO (facultatif) et quelques neurones.<span id="more-631"></span></p>
<h3>Le pourquoi du BSOD</h3>
<p>Avant de mettre les mains dans le cambouis, il est intéressant de comprendre pourquoi Windows affiche un écran bleu. Cet écran maléfique est affiché lorsque quelque chose d&rsquo;assez sérieux s&rsquo;est produit au niveau du noyau. Cela peut être aussi bien matériel que logiciel (parfois les deux). Par exemple : un driver tente d&rsquo;accéder à une zone mémoire non existante ou protégée. Si vous essayez de faire cela avec un programme en en mode utilisateur, celui-ci crashera en affichant un message d&rsquo;erreur Windows (ou une <em>segmentation fault</em> sous Linux). En mode noyau, l&rsquo;équivalent est le BSOD sous Windows (<em>Kernel Panic</em> sous Linux) et vous n&rsquo;avez pas d&rsquo;autre choix que de rebooter votre bécane. Eh oui, on ne plaisante pas avec le kernel. Voici un exemple de driver qui provoquera un écran bleu à coup sûr :</p>
<pre>* (unsigned int *) 0 = 0;</pre>
<p>Ce code essaye d&rsquo;écrire 0 à l&rsquo;adresse mémoire virtuelle 0, qui est invalide. Par conséquent, le processeur déclenchera un défaut de page, ce qui provoque un écran bleu puisque son descripteur est invalide. Il y a plein d&rsquo;autres manières de provoquer un écran bleu, mais cela dépasse le cadre de cet article.</p>
<h3>Reversing de la routine du BSOD</h3>
<p>Le code de la routine affichant le BSOD se situe dans le kernel Windows, dans ntoskrnl.exe (ou ntkrnlpa.exe si vous avez la PAE). Après avoir débuggé une machine virtuelle et provoqué un écran bleu volontairement grâce au code donné ci-dessus, je m&rsquo;aperçois que la VM s&rsquo;est arrêtée dans la routine <code>KeBugCheckEx</code>. J&rsquo;ouvre ntoskrnl.exe avec IDA PRO et désassemble cette routine.</p>
<pre>public _KeBugCheckEx@20
_KeBugCheckEx@20 proc near

BugCheckCode= dword ptr  8
BugCheckParameter1= dword ptr  0Ch
BugCheckParameter2= dword ptr  10h
BugCheckParameter3= dword ptr  14h
BugCheckParameter4= dword ptr  18h

mov     edi, edi
push    ebp
mov     ebp, esp
push    0
push    [ebp+BugCheckParameter4]
push    [ebp+BugCheckParameter3]
push    [ebp+BugCheckParameter2]
push    [ebp+BugCheckParameter1]
push    [ebp+BugCheckCode]
call    _KeBugCheck2@24 ; KeBugCheck2(x,x,x,x,x,x)
pop     ebp
retn    14h
_KeBugCheckEx@20 endp</pre>
<p>Cette fonction est très courte, elle ne fait qu&rsquo;empiler des paramètres et appeler la routine <code>KeBugCheck2</code>. Cette dernière est par contre très longue. Comme mon but n&rsquo;est pas de la reverser intégralement mais juste isoler la partie qui m&rsquo;intéresse, je parcours rapidement son graphe avec IDA. Vu le nom des fonctions appelées, cette routine récupère des informations auprès des drivers sur le crash qui vient d&rsquo;avoir lieu.</p>
<h3>Couleur de fond</h3>
<p>A peu près au milieu de la fonction, on tombe sur ce code :</p>
<pre>call    _InbvAcquireDisplayOwnership@0 ; InbvAcquireDisplayOwnership()
call    _InbvResetDisplay@0 ; InbvResetDisplay()
push    4
push    1DFh
mov     ebx, 27Fh
push    ebx
push    esi
push    esi
call    _InbvSolidColorFill@20 ; InbvSolidColorFill(x,x,x,x,x)</pre>
<p>Apparemment, on a affaire à des appels de fonction gérant l&rsquo;affichage. On commence par faire un <em>reset </em>de l&rsquo;affichage, puis on appelle la routine <code>InvbSolidColorFill</code>. Les paramètres qui lui sont passés sont les suivants (je rappelle que l&rsquo;ordre est inversé, selon la convention d&rsquo;appel utilisé) :</p>
<ul>
<li>deux arguments égaux à 0 (si on cherche un peu plus haut on trouve un <code>xor esi,esi</code> donc esi = 0)</li>
<li>0x27F = 639</li>
<li>0x1DF = 479</li>
<li>4</li>
</ul>
<p>Etant astucieux, on se rend compte que 639 = 640 &#8211; 1 et 479 = 480 &#8211; 1. Hors, 640 x 480 correspond exactement à la résolution de l&rsquo;écran bleu. Avec les deux paramètres 0 qui précèdent, ces valeurs correspondent aux bornes (gauche, haute, droite, et basse) de la zone de l&rsquo;écran à remplir. La couleur de remplissage est précisée par le dernier paramètre, qui vaut 4. En cherchant un peu sur Google, on se rend compte que le code couleur utilisé par cette fonction est sur 4 bits : IBGR soit Intensity, Blue, Green and Red. 4 en décimal équivaut à 0100 en binaire, soit 1 pour le bleu et 0 pour le reste. Voilà donc pourquoi l&rsquo;écran bleu est bleu ! <img src='http://www.segmentationfault.fr/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Si on désassemble la fonction <code>InvbSolidColorFill</code>, on se rend compte qu&rsquo;assez rapidement, celle-ci appelle la fonction <code>VidSolidColorFill</code>. Il s&rsquo;agit d&rsquo;une fonction importée par ntoskrnl.exe depuis bootvid.dll, le module chargé de la vidéo lors du boot. Son code est relativement peu clair, aussi j&rsquo;ai préféré jeter un coup d&rsquo;oeil aux sources de ReactOS, qui est nettement plus lisible. Pour ceux qui ne connaissent pas, il s&rsquo;agit d&rsquo;un projet visant à recoder Windows en Open Source. Voici le code de la fonction dans ReactOS (qui doit être très similaire dans Windows) :</p>
<pre>VOID NTAPI
VidSolidColorFill(IN ULONG Left, IN ULONG Top,
                  IN ULONG Right, IN ULONG Bottom,
                  IN UCHAR Color)
{
    int y, x;

	for (y = Top; y &lt;= Bottom; y++)
	{

            for (x = Left; x &lt;= Right; x++)
            {
                //
                // Draw the pixel
                //
                VidpSetPixel(x, y, Color);
            }
	}
}</pre>
<p>Comme vous pouvez le voir, on peut difficilement faire plus simple. Une fonction chargée de fixer la couleur d&rsquo;un pixel est appelée dans une double boucle, ce qui a pour effet de remplir l&rsquo;écran.</p>
<h3>Couleur du texte</h3>
<p>Revenons au code de <code>KeBugCheck2</code>. Juste après le code qui remplit l&rsquo;écran, on a ceci :</p>
<pre>push    0Fh
call    _InbvSetTextColor@4 ; InbvSetTextColor(x)</pre>
<p>Vu le nom de la fonction, on peut se douter que celle-ci fixe la couleur du texte du BSOD. 0xF = 0b1111 = blanc. Que demander de plus ?</p>
<h3>Patching à chaud pour changer les couleurs</h3>
<p>Que diriez vous de personnaliser la couleur du BSOD sur votre système ? Je n&rsquo;ai personnellement jamais aimé le bleu, je préfère le rouge (plus sexy pour un message d&rsquo;erreur !). Quand au texte, du jaune devrait faire l&rsquo;affaire&#8230;</p>
<p>Pour des raisons de sécurité, je vous déconseille fortement d&rsquo;éditer l&rsquo;exécutable de votre noyau (ntoskrnl.exe) car une erreur peut être vraiment fatale. Je préfère nettement opérer en mémoire, afin qu&rsquo;un simple reboot efface les modifications. D&rsquo;autre part, comme on s&rsquo;apprête à débugger Windows et à le faire planter, il faut opérer sur une deuxième machine. Munissez vous d&rsquo;une VM (VirtualBox pour ma part) que vous bootez en mode debug (flag /debug du boot.ini) avec Windbg lancée en parallèle sur votre machine. Pour ceux qui débutent, je vous conseille de lire <a href="http://0vercl0k.blogspot.com/2008/02/first-steps-into-ring0.html">cet article</a> d&rsquo;0vercl0ck qui vous expliquera comment tout configurer comme il faut. Prêt ? C&rsquo;est parti !</p>
<p>Une fois Windows démarré, freezez le avec Ctrl+Pause sous Windbg. Commençons par localiser ou se trouve l&rsquo;appel à <code>InvbSolidColorFill</code> dans <code>KeBugCheck2</code>. Sous IDA, on effectue un petit calcul d&rsquo;offset pour savoir ou se trouve le <code>push 4</code> par rapport au début de <code>KeBugCheck2</code>. Chez moi, j&rsquo;ai un offset de 0x60D. Dans Windbg, je tape donc <code>u KeBugCheck2+0x60d</code>. Cependant, ça ne tombe pas juste ; j&rsquo;atterris après ce bout de code (facile de le constater avec IDA). C&rsquo;est sans doute à cause du fait que j&rsquo;ai des mises à jours différentes sur ma machine et dans ma VM. Je remonte donc petit à petit et je finir par arriver sur l&rsquo;instruction qui m&rsquo;intéresse :</p>
<pre>kd&gt; u KeBugCheck2+0x5e4
nt!KeBugCheck2+0x5e4:
8053342e e8da9fffff      call    nt!InbvResetDisplay (8052d40d)
80533433 6a04            push    4
80533435 68df010000      push    1DFh
8053343a bb7f020000      mov     ebx,27Fh
8053343f 53              push    ebx
80533440 56              push    esi
80533441 56              push    esi
80533442 e84aa0ffff      call    nt!InbvSolidColorFill (8052d491)</pre>
<p>Il suffit de patcher la valeur située à l&rsquo;adresse <code>80533434</code> pour changer la couleur du BSOD ! Pour ma part, je choisis le rouge, soit 0b0001 = 1. Je tape donc ceci dans Windbg (eb = edit byte) :</p>
<pre>kd&gt; eb 80533434 01</pre>
<p>Vérifions cela en désassemblant à nouveau :</p>
<pre>kd&gt; u KeBugCheck2+0x5e4
nt!KeBugCheck2+0x5e4:
8053342e e8da9fffff      call    nt!InbvResetDisplay (8052d40d)
80533433 6a01            push    1
80533435 68df010000      push    1DFh
8053343a bb7f020000      mov     ebx,27Fh
8053343f 53              push    ebx
80533440 56              push    esi
80533441 56              push    esi
80533442 e84aa0ffff      call    nt!InbvSolidColorFill (8052d491)</pre>
<p>Super, ça semble avoir marché. Faisons de même avec la couleur du texte !</p>
<pre>kd&gt; u KeBugCheck2+0x5fd
nt!KeBugCheck2+0x5fd:
80533447 6a0f            push    0Fh
80533449 e8d1a0ffff      call    nt!InbvSetTextColor (8052d51f)</pre>
<p>Je veux du jaune, je remplace donc le 0x0F par un 0x0B soit 0b1011 (mélange clair de vert et rouge).</p>
<pre>kd&gt; eb 80533448 0B
kd&gt; u KeBugCheck2+0x5fd
nt!KeBugCheck2+0x5fd:
80533447 6a0b            push    0Bh
80533449 e8d1a0ffff      call    nt!InbvSetTextColor (8052d51f)</pre>
<p>Nikel. Il ne reste plus qu&rsquo;à provoquer un écran bleu ! Pour ce faire à partir de Windbg, c&rsquo;est très simple : il suffit de mettre eip à 0. On tape juste <code>r eip = 0</code> et on débloque la machine avec la commande <code>g</code>. Windows crashe instantanément et Windbg reprend la main. Attendez quelques secondes que les symboles se rechargent, appuyez sur Ctrl+Pause pour arrêter l&rsquo;opération de diagnostique de crash, et retapez <code>g</code> pour voir apparaître votre beau BSOD personnalisé. En ce qui me concerne, c&rsquo;est plutôt un RSOD (Red Screen Of Death) !</p>
<div id="attachment_635" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.segmentationfault.fr/wp-content/uploads/2009/04/rsod.png"><img class="size-medium wp-image-635" title="RSOD" src="http://www.segmentationfault.fr/wp-content/uploads/2009/04/rsod-300x225.png" alt="Red Screen Of Death" width="300" height="225" /></a><p class="wp-caption-text">Red Screen Of Death</p></div>
<p>C&rsquo;est ti pas mignon tout ça ? Pour ceux qui par malheur verraient leur écran s&rsquo;afficher puis disparaître à cause d&rsquo;un reboot instantané, refaites la manip en n&rsquo;oubliant pas au préalable de désactiver les reboots sur crash système en faisant un clic droit sur le poste de travail, propriétés, avancé, paramètres de démarrage et récupération, puis décochez la case &laquo;&nbsp;redémarrer automatiquement&nbsp;&raquo;.</p>
<h3>Conclusion</h3>
<p>J&rsquo;espère que cet article vous aura plu et que vous allez dès à présent tuner votre BSOD pour rendre jaloux vos amis. Pour ceux qui voudraient aller plus loin, sachez qu&rsquo;il est également possible de modifier le texte affiché sur l&rsquo;écran&#8230; Après, vous pouvez intégrer tout ça dans un driver qui se chargera d&rsquo;effectuer le patching lui-même. C&rsquo;est ce que fait le programme BSOD Hack (cf en bas). Et si vous en avez le courage, vous pouvez même faire un petit hook inline (detour patching) afin de rediriger un crash vers votre propre routine. J&rsquo;ai entendu dire que certains avaient réussi à charger et afficher une image de bière lors d&rsquo;un crash, si ça peut vous donner des idées&#8230; <img src='http://www.segmentationfault.fr/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<h3>Références</h3>
<ul>
<li><a href="http://www.rohitab.com/discuss/index.php?showtopic=23767">BSOD Hack</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.segmentationfault.fr/securite-informatique/tunnez-votre-bsod-blue-screen-of-death/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Problèmes liés aux interruptions</title>
		<link>http://www.segmentationfault.fr/securite-informatique/problemes-lies-aux-interruptions/</link>
		<comments>http://www.segmentationfault.fr/securite-informatique/problemes-lies-aux-interruptions/#comments</comments>
		<pubDate>Tue, 21 Apr 2009 18:52:31 +0000</pubDate>
		<dc:creator>Emilien Girault</dc:creator>
				<category><![CDATA[Développement]]></category>
		<category><![CDATA[Reverse Engineering]]></category>
		<category><![CDATA[Sécurité informatique]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[drivers]]></category>
		<category><![CDATA[hacking]]></category>
		<category><![CDATA[kernel]]></category>
		<category><![CDATA[ring 0]]></category>
		<category><![CDATA[x86]]></category>

		<guid isPermaLink="false">http://www.segmentationfault.fr/?p=609</guid>
		<description><![CDATA[Dans le cadre de mon stage, je m&#8217;intéresse au fonctionnement des interruptions de l&#8217;architecture x86. Il s&#8217;agit d&#8217;un mécanisme complexe mais extrêmement important pour comprendre comment un système d&#8217;exploitation arrive à fonctionner. Si j&#8217;écris ce post, c&#8217;est parce que je me suis pris la tête sur des problèmes qui y sont liés&#8230;  Je viens d&#8217;en [...]]]></description>
			<content:encoded><![CDATA[<p>Dans le cadre de mon stage, je m&rsquo;intéresse au fonctionnement des interruptions de l&rsquo;architecture x86. Il s&rsquo;agit d&rsquo;un mécanisme complexe mais extrêmement important pour comprendre comment un système d&rsquo;exploitation arrive à fonctionner. Si j&rsquo;écris ce post, c&rsquo;est parce que je me suis pris la tête sur des problèmes qui y sont liés&#8230;  Je viens d&rsquo;en trouver les causes, et je pense que cela pourra en intéresser plus d&rsquo;un.<span id="more-609"></span></p>
<h3>Généralités sur les interruptions</h3>
<p>Une interruption est un événement particulier qui peuvent se produire lors de l&rsquo;exécution d&rsquo;un programme. A chaque type d&rsquo;interruption est associé un numéro appelé <em>vecteur d&rsquo;interruption</em>, connu du ou des processeur(s). Pour simplifier, les interruptions peuvent provenir de deux sources : le logiciel et le matériel. Les interruptions matérielles sont générées par les périphériques (clavier, souris, cartes, timers, disques durs&#8230;) et sont transmises au processeur par l&rsquo;APIC (<em>Advanced Programmable Interrupt Controller</em>).  Les interruptions logicielles peuvent être quant à elles déclenchées volontairement par une instruction (<em>int</em>) ou de façon accidentelle par une erreur arithmétique, logique, de protection, etc. Dans ce cas, on parle souvent d&rsquo;<em>exception</em> et de <em>fautes</em>.</p>
<p>Généralement, les interruptions (aussi bien matérielles que logicielles) sont susceptibles de se déclencher à n&rsquo;importe quel moment dans l&rsquo;exécution d&rsquo;un programme, et chaque processeur doit savoir comment traiter chacune d&rsquo;entre elles. A chaque vecteur d&rsquo;interruption on associe alors un <em>handler d&rsquo;interruption</em>, qui est une fonction qui sera appelée automatiquement quand l&rsquo;interruption sera générée.  On place ces fonctions dans une table, l&rsquo;IDT, pour <em>Interrupt Descriptor Table</em>. Il est important de noter qu&rsquo;il y a une IDT par processeur, afin que chacun puisse avoir si besoin un comportement différent pour chaque interruption.</p>
<p>Il existe deux types d&rsquo;interruptions matérielles, les masquables (les IRQ) et les non masquables (la NMI et la SMI) qu&rsquo;on ne traitera pas ici en raison de leur grande particularité. Chaque interruption matérielle possède une priorité, qui est gérée par l&rsquo;APIC. Pour faire simple, ce composant est relié aux périphériques par des lignes d&rsquo;IRQ (Interrupt Requests) et se charge de faire le médiateur entre tous ces périphériques et le ou les processeur(s). Son rôle est en gros de transformer ces IRQ en demandes d&rsquo;interruptions avec le vecteur associé.  Comme plusieurs IRQ peuvent intervenir en même temps, l&rsquo;APIC définit des priorités afin de transmettre les plus urgentes d&rsquo;abord.</p>
<p>Dans certains cas, le processeur peut ne pas vouloir être dérangé par une interruption. C&rsquo;est le cas par exemple lorsqu&rsquo;il est en train de modifier des structures globales en mémoire. Il a alors la possibilité d&rsquo;ignorer les interruptions qu&rsquo;il va recevoir de deux manières. La première, que je ne détaillerai pas, est de ne masquer que celles dont la priorité est inférieure à un certain seuil (appelé IRQL sous Windows) en communiquant avec l&rsquo;APIC. La deuxième est de masquer la totalité des interruptions et c&rsquo;est celle que nous allons détailler.</p>
<h3>Subtilité sur le masquage</h3>
<p>C&rsquo;est le registre EFLAGS  et plus précisément son bit IF (bit 9) qui contrôle si les interruptions masquables sont activées ou non. Ce bit est modifiable par l&rsquo;intermédiaire des instructions <code>cli</code> pour masquage et <code>sti</code> pour démasquage, ou bien en utilisant <em>pushf</em> / <em>popf</em> associés à des masques.</p>
<p>Attention, le masquage des interruptions n&rsquo;affecte que les interruptions matérielles ! Les interruptions logicielles (ainsi que les interruptions NMI et SMI, très particulières) ne sont pas affectées par ces opérations. Autrement dit, vous aurez beau baisser l&rsquo;IRQL ou faire un <code>cli</code>, une exception due à une division par zéro ou à un défaut de page pourra toujours survenir.</p>
<h3>Problème n°1 : DbgPrint(), c&rsquo;est le mal</h3>
<p>J&rsquo;ai fait tous mes tests en machine virtuelle. Comme le développement de driver n&rsquo;est jamais sûr à 100% et que je voulais tout de même avoir quelque chose de fonctionnel, j&rsquo;ai réalisé un petit script qui charge le driver et le décharge 100 fois de suite, en lançant en plus des programmes divers pour solliciter l&rsquo;OS un maximum. Le tout étant de prouver que le driver n&rsquo;explose pas à la première interruption, bien entendu.</p>
<p>Dans mon cas, je devais hooker l&rsquo;interruption n°14 correspondant au défaut de page (<em>page fault</em>), en insérant du code avant de rappeler le handler par défaut de Windows. Je rappelle que cette exception (logicielle) se produit quand une page virtuelle n&rsquo;est mappée à aucune adresse physique (soit parce qu&rsquo;elle a été swappée sur disque, soit parce qu&rsquo;elle n&rsquo;existe tout simplement pas). Cela se produit quand on tente d&rsquo;accéder à une page dont le descripteur PTE a son premier bit (bit P) à 0.</p>
<p>J&rsquo;ai donc commencé par concevoir un handler minimal qui ne faisait rien à part empiler tous les registres, les dépiler puis appeler le handler de Windows, <code>KiTrap0E</code>. Jusqu&rsquo;ici, tout fonctionne, sauf que je n&rsquo;ai pas vraiment de preuve que ma routine est appelée (vu que je n&rsquo;ai aucune trace).</p>
<p>Je me décide donc à insérer des <code>DbgPrint()</code> dans le code de la routine. Et là, c&rsquo;est le drame : j&rsquo;obtiens des traces certes, mais j&rsquo;en obtiens tellement que la VM freeze ou affiche un écran bleu au bout de quelques secondes. Il faut croire que les défauts de page sont très nombreux sous Windows&#8230; Mais pourquoi ça plante maintenant et pas avant ? L&rsquo;explication est liée au visualisateur de traces (j&rsquo;utilise DebugView). Lorsque <code>DbgPrint()</code> est appelé, le message est récupéré par le noyau puis par DebugView. Je ne sais pas exactement pourquoi, mais apparemment quand il y a beaucoup de messages de récupérés, DebugView commence à provoquer des défauts de page (probablement à cause du fait qu&rsquo;il se fait swapper par l&rsquo;OS). Comme ces défauts de pages sont à leur tour catchés par mon handler, ils entraînent d&rsquo;autres appels à <code>DbgPrint()</code>&#8230; Bref, une belle boucle qui finit par exploser tôt ou tard.</p>
<p>Au final, je renonce donc  à afficher des traces, vu que cela perturbe plus le système qu&rsquo;autre chose. En plus j&rsquo;ai ma preuve que mon handler est appelé, vu que ça plante <img src='http://www.segmentationfault.fr/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<h3>Problème n°2 : sti, c&rsquo;est aussi le mal</h3>
<p>Le réel but de mon handler est de modifier une structure assez cruciale du noyau sous certaines conditions. Afin d&rsquo;éviter que cette modification entraîne des problèmes de concurrence, je décide de masquer les interruptions avant le traitement (<code>cli</code>), et de les démasquer ensuite à l&rsquo;aide de  et <code>sti</code>. Je lance le driver. Pas de crash. Je commence à crier victoire, et au moment ou je lance mon script de déchargement, j&rsquo;ai le droit à un écran bleu. Je regarde le code de déchargement, il ne fait absolument rien de méchant. Je relance, idem. Je finis par comprendre que ce n&rsquo;est pas le déchargement du driver qui foire, mais juste le fait de lancer un programme, car cela provoque un défaut de page&#8230; C&rsquo;est donc bien mon handler qui pose problème, mais où ?</p>
<p>Je supprime ma modification de variable globale, ça plante toujours. Pourtant je n&rsquo;ai plus que <code>cli</code> et <code>sti</code> dans mon handler (en plus de l&rsquo;appel au handler par défaut). Je retire <code>sti</code> et je constate que ça marche ! C&rsquo;est donc cette instruction qui est responsable du plantage du driver&#8230; mais pourquoi ? En fait, il se trouve que lors des appels au handler de défaut de page, les interruptions sont <em>déjà masquées</em>. C&rsquo;est dû au fait que l&rsquo;interruption correspondant au défaut de page possède un descripteur dans l&rsquo;IDT qui précise que l&rsquo;IF doit être mis à 0 lors de l&rsquo;appel du handler (c&rsquo;est une <em>interrupt gate</em>, selon Intel). Ainsi, lors de l&rsquo;appel au handler, l&rsquo;instruction <code>cli</code> ne fait absolument rien (le bit IF d&rsquo;EFLAGS est déjà à 0)&#8230; Le problème, c&rsquo;est que <code>sti</code> le passe à 1, ce qui autorise les interuptions ! Si jamais le défaut de page s&rsquo;est produit dans une zone critique de l&rsquo;OS et qu&rsquo;une interruption survient précisément à ce moment, le kernel se vautre. Cela ne se produit peut-être pas à tous les coups, mais croyez moi, ça arrive (faites le test pour vous en convaincre).</p>
<p>Comment patcher cela ? Ne pas masquer les interruptions dans un handler de défaut de page, puisqu&rsquo;elles le sont déjà. La solution, c&rsquo;est tout simplement de ne rien faire <img src='http://www.segmentationfault.fr/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<h3>Conclusion</h3>
<p>Morale de l&rsquo;histoire : utiliser <code>DbgPrint()</code> ou <code>sti</code> dans un handler de défaut de page est une mauvaise idée. Pour déboguer, préférez utiliser des variables globales plutôt que des fonctions à effet de bords incontrôlables. Et ne cherchez pas à masquer (et surtout à démasquer) les interruptions qui le sont déjà . J&rsquo;espère que ce post vous aura épargné un long moment de galère. En tout cas, j&rsquo;aurais aimé en lire un du même type plus tôt !</p>
]]></content:encoded>
			<wfw:commentRss>http://www.segmentationfault.fr/securite-informatique/problemes-lies-aux-interruptions/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Plongeon dans les appels systèmes Windows</title>
		<link>http://www.segmentationfault.fr/reversing/plongeon-dans-les-appels-systemes-windows/</link>
		<comments>http://www.segmentationfault.fr/reversing/plongeon-dans-les-appels-systemes-windows/#comments</comments>
		<pubDate>Sat, 28 Mar 2009 10:53:26 +0000</pubDate>
		<dc:creator>Emilien Girault</dc:creator>
				<category><![CDATA[Reverse Engineering]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[ring 0]]></category>

		<guid isPermaLink="false">http://www.segmentationfault.fr/?p=593</guid>
		<description><![CDATA[Mon stage m&#8217;a donné l&#8217;occasion d&#8217;analyser en détails comment un appel système est réalisé sous Windows. Si vous vous demandez comment un programme utilisateur (ring 3) fait pour appeler une fonction s&#8217;exécutant en mode noyau (ring 0), alors cet article est pour vous. J&#8217;y explique toutes les étapes de la chaîne en partant du début [...]]]></description>
			<content:encoded><![CDATA[<p>Mon stage m&rsquo;a donné l&rsquo;occasion d&rsquo;analyser en détails comment un appel système est réalisé sous Windows. Si vous vous demandez comment un programme utilisateur (ring 3) fait pour appeler une fonction s&rsquo;exécutant en mode noyau (ring 0), alors cet article est pour vous. J&rsquo;y explique toutes les étapes de la chaîne en partant du début (l&rsquo;appel de fonction dans un programme quelconque) pour arriver au code de l&rsquo;API en mode noyau. Pour lire cet article, des bases d&rsquo;assembleur sont indispensables.<span id="more-593"></span></p>
<h3>Privilèges des processeurs x86</h3>
<p>Avant d&rsquo;aborder le sujet, il est nécessaire de bien comprendre une subtilité des processeurs x86 : les niveaux de privilèges. Un processeur est censé exécuter du code machine produit par un compilateur / assembleur. Le code qui s&rsquo;exécute à un instant t a accès à certains privilèges qui dépendent du niveau de privilège dans lequel se trouve le processeur. Ce niveau, aussi appelé <em>ring</em>, ou <em>anneau</em>, est un entier codé sur deux bits. Il peut donc prendre 4 valeurs : 0, 1, 2, et 3. Plus ce nombre est petit, plus les privilèges sont élevés ; plus il est grand, plus ils sont restreints. Le ring 0 est appelé <em>mode superviseur</em>, ou <em>kernelland</em>,et c&rsquo;est sous ce mode que tournent 99% des noyaux d&rsquo;OS (Windows et Linux en font partie). Les programmes utilisateurs s&rsquo;exécutent quant à eux en ring 3, appelé <em>mode utilisateur</em> ou <em>userland</em>.</p>
<p>Le niveau de privilège courant du processeur est appelé CPL (Current Privilege Level). En interne, le CPL est stocké dans les deux premiers bits des registres CS et SS. La règle générale est la suivante : il n&rsquo;est pas possible d&rsquo;exécuter des instructions nécessitant un niveau de privilège inférieur au CPL. De même, il n&rsquo;est pas directement possible de demander au processeur de changer le CPL vers un niveau inférieur. On peut donc se demander : comment est-ce possible d&rsquo;appeler une routine du noyau depuis un code utilisateur ? C&rsquo;est là tout l&rsquo;objet de cet article&#8230;</p>
<h3>Un programme d&rsquo;exemple</h3>
<p>Afin d&rsquo;analyser comment se déroule un appel système, nous allons commencer par coder un programme d&rsquo;exemple en C.</p>
<pre>#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;windows.h&gt;

int main(int argc, char *argv[])
{
    HANDLE handle;
    WIN32_FIND_DATA findData;

    handle = FindFirstFile(".", &amp;findData);

    printf("Handle = %dn", handle);

    getchar();

    return 0;
}</pre>
<p>Ce programme appelle l&rsquo;API Windows <code>FindFirstFile</code>. Cette fonction prend en paramètre un nom de dossier et retourne un handle vers le premier fichier de ce dossier. Je suis d&rsquo;accord : ce programme ne sert pas à grand chose, à part appeler une API Windows, mais c&rsquo;est justement le but.</p>
<h3>Tracing en userland</h3>
<p>Pour information, j&rsquo;ai réalisé tous ces tests sur un Windows XP SP3 français, avec Dev-C++ et GCC 3.4.2. Une fois le programme compilé, on peut utiliser un débogeur pour suivre l&rsquo;exécution du programme. Lançons OllyDbg et observons le <code>main()</code> du programme :</p>
<pre>00401290  /$ 55             PUSH EBP
00401291  |. 89E5           MOV EBP,ESP
00401293  |. 81EC 78010000  SUB ESP,178
00401299  |. 83E4 F0        AND ESP,FFFFFFF0
0040129C  |. B8 00000000    MOV EAX,0
004012A1  |. 83C0 0F        ADD EAX,0F
004012A4  |. 83C0 0F        ADD EAX,0F
004012A7  |. C1E8 04        SHR EAX,4
004012AA  |. C1E0 04        SHL EAX,4
004012AD  |. 8985 A4FEFFFF  MOV DWORD PTR SS:[EBP-15C],EAX
004012B3  |. 8B85 A4FEFFFF  MOV EAX,DWORD PTR SS:[EBP-15C]
004012B9  |. E8 82040000    CALL syscalls.00401740
004012BE  |. E8 1D010000    CALL syscalls.004013E0
004012C3  |. 8D85 A8FEFFFF  LEA EAX,DWORD PTR SS:[EBP-158]           ; |
004012C9  |. 894424 04      MOV DWORD PTR SS:[ESP+4],EAX             ; |
004012CD  |. C70424 0030400&gt;MOV DWORD PTR SS:[ESP],syscalls.00403000 ; |ASCII "fg"
004012D4  |. E8 E7050000    CALL &lt;JMP.&amp;KERNEL32.FindFirstFileA&gt;      ; FindFirstFileA
004012D9  |. 83EC 08        SUB ESP,8
004012DC  |. 8945 F4        MOV DWORD PTR SS:[EBP-C],EAX             ; |
004012DF  |. 8B45 F4        MOV EAX,DWORD PTR SS:[EBP-C]             ; |
004012E2  |. 894424 04      MOV DWORD PTR SS:[ESP+4],EAX             ; |
004012E6  |. C70424 0330400&gt;MOV DWORD PTR SS:[ESP],syscalls.00403003 ; |ASCII "Handle = %d"
004012ED  |. E8 4E050000    CALL &lt;JMP.&amp;msvcrt.printf&gt;                ; printf
004012F2  |. E8 39050000    CALL &lt;JMP.&amp;msvcrt.getchar&gt;               ; [getchar
004012F7  |. B8 00000000    MOV EAX,0
004012FC  |. C9             LEAVE
004012FD  . C3             RETN</pre>
<p>Je rappelle que nous sommes à présent dans un programme utilisateur, donc en userland. Il est facile de le vérifier en regardant la valeur de CS. Chez moi, c'est 0x2B, soit 0b101011. Les deux premiers bits (poids faible) sont bien 0b11, correspondant au ring 3.</p>
<p>L'appel à <code>FindFirstFile</code> se trouve en <code>004012D4</code>, après que les paramètres aient été mis sur la pile. Après avoir placé un breakpoint sur le call (F2), et lancé l'exécution (F9), le programme s'arrête dessus. On fait un <em>step in</em> (F7) pour suivre le call.</p>
<pre>004018C0   $-FF25 B8504000  JMP DWORD PTR DS:[&lt;&amp;KERNEL32.FindFirstFileA&gt;]</pre>
<p>Nous nous situons à présent dans une zone appelée <em>trampoline</em>. Cette zone fait référence à l&rsquo;IAT (Import Address Table) de l&rsquo;exécutable, qui contient les adresses des fonctions importées. Pour faire le parallèle avec Linux, le trampoline est l&rsquo;équivalent de la section .plt, et l&rsquo;IAT joue le même rôle que la section .got. Pour plus d&rsquo;informations sur ces sections je vous conseille de lire <a href="http://www.segmentationfault.fr/linux/role-plt-got-ld-so/">cet article</a>.</p>
<p>Le jump fait référence à un pointeur situé en 004050B8, qui contient l&rsquo;adresse de la fonction <code>FindFirstFileA</code>. On rappuie sur F7 pour suivre l&rsquo;appel. On arrive alors dans la section .text de kernel32.dll, qui a été chargée à l&rsquo;exécution.</p>
<pre>7C813869 &gt; 8BFF             MOV EDI,EDI
7C81386B   55               PUSH EBP
7C81386C   8BEC             MOV EBP,ESP
7C81386E   81EC 6C020000    SUB ESP,26C
...
7C813894   56               PUSH ESI
7C813895   56               PUSH ESI
7C813896   56               PUSH ESI
7C813897   8D8D ACFDFFFF    LEA ECX,DWORD PTR SS:[EBP-254]
7C81389D   51               PUSH ECX
7C81389E   56               PUSH ESI
7C81389F   FF70 04          PUSH DWORD PTR DS:[EAX+4]
7C8138A2   E8 66B2FFFF      CALL kernel32.FindFirstFileExW</pre>
<p>On s&rsquo;aperçoit que cette fonction en appelle une autre, <code>FindFirstFileExW</code>, toujours dans kernel32. Pourquoi ? Simplement parce que la plupart des fonctions internes de Windows utilisent un encodage Unicode, et non pas ASCII. Dans la convention Windows, les fonctions se terminant par un A gèrent l&rsquo;ASCII, et celles en W gèrent l&rsquo;Unicode. En interne, les fonctions ASCII convertissent les paramètres passés en Unicode, et appèlent les fonctions Unicode correspondantes. C&rsquo;est le call que nous venons de voir. Suivons le.</p>
<pre>7C80EB0D &gt; 8BFF             MOV EDI,EDI
7C80EB0F   55               PUSH EBP
7C80EB10   8BEC             MOV EBP,ESP
7C80EB12   81EC CC020000    SUB ESP,2CC
...
7C80EC66   57               PUSH EDI
7C80EC67   8D85 90FDFFFF    LEA EAX,DWORD PTR SS:[EBP-270]
7C80EC6D   89B5 40FDFFFF    MOV DWORD PTR SS:[EBP-2C0],ESI
7C80EC73   8B35 1410807C    MOV ESI,DWORD PTR DS:[&lt;&amp;ntdll.NtOpenFile&gt;] ; ZwOpenFile
7C80EC79   50               PUSH EAX
7C80EC7A   C785 34FDFFFF 18&gt;MOV DWORD PTR SS:[EBP-2CC],18
7C80EC84   FFD6             CALL ESI
...
7C80ED46   FFB5 90FDFFFF    PUSH DWORD PTR SS:[EBP-270]
7C80ED4C   FF15 2812807C    CALL DWORD PTR DS:[&lt;&amp;ntdll.NtQueryDirectoryFile&gt;]</pre>
<p>On voit que cette fonction réalise plusieurs appels (ici je n&rsquo;en n&rsquo;ai affiché que 2 mais il y en a d&rsquo;autres) dans ntdll.dll, une autre DLL chargée. Continuons notre traçing en explorant l&rsquo;appel à <code>ZwOpenFile</code>.</p>
<pre>7C91D580 &gt; B8 74000000      MOV EAX,74
7C91D585   BA 0003FE7F      MOV EDX,7FFE0300
7C91D58A   FF12             CALL DWORD PTR DS:[EDX]  ; <code>ntdll.KiFastSystemCall</code>
7C91D58C   C2 1800          RETN 18</pre>
<h3>Transition vers le mode noyau</h3>
<p>Nous sommes à présent dans ntdll.dll, dans la fonction <code>ZwOpenFile</code> exportée par la dll. Comme vous le voyez, la fonction est très courte. La première instruction place 0&#215;74 dans EAX, qui correspond au numéro de la fonction du noyau qui va être appelée. On a ensuite un appel à une fonction nommée <code>KiFastSystemCall</code>. C&rsquo;est elle qui va réaliser le passage en mode noyau, à l&rsquo;aide des instructions suivantes :</p>
<pre>7C91E4F0 &gt; 8BD4             MOV EDX,ESP
7C91E4F2   0F34             SYSENTER
7C91E4F4 &gt; C3               RETN</pre>
<p>C&rsquo;est précisément SYSENTER qui réalise la transition. Mais que fait donc cette instruction ? On ouvre le manuel Intel 2B au chapitre 4.1, instruction SYSENTER. On y apprend que cette instructionpermet d&rsquo;exécuter des appels systèmes. Historiquement, les appels systèmes étaient exécutés en utilisant les interruptions logicielles, avec l&rsquo;instruction INT 2E sous Windows (et INT 80 sous Linux). SYENTER étant plus rapide, elle a succédé à l&rsquo;ancienne méthode, qui reste toutefois disponible pour des raisons de compatibilité.</p>
<p>Contrairement aux interruptions, SYSENTER n&rsquo;utilise pas de table de pointeurs, mais des registres spéciaux du processeur, appelés MSR (pour Model Specific Register). Ces registres sont assez particuliers ; ils possèdent un numéro et sont accessibles en lecture et écriture via les instructions <code>rdmsr</code> et <code>wrmsr</code>. SYSENTER en utilise 3 :</p>
<ul>
<li>IA32_SYSENTER_CS (0&#215;174) correspond à la valeur à charger dans CS quand SYSENTER sera appelé</li>
<li>IA32_SYSENTER_ESP (0&#215;175) sera quant à lui chargé dans ESP</li>
<li>IA32_SYSENTER_EIP (0&#215;176) sera chargé dans EIP</li>
</ul>
<p>Ainsi, ces trois registres définissent tout ce qu&rsquo;il faut pour exécuter un bout de code en mode en mode noyau, puisque CS (et donc ses deux premiers bits, encodant le CPL) sera changé.</p>
<p>Ces registres ne sont pas lisibles en mode utilisateur ; il faut impérativement être en ring 0 pour les lire. Pour cela, utilisons Windbg, le débogueur noyau de Microsoft. Il se télécharge <a href="http://www.microsoft.com/whdc/devtools/debugging/installx86.mspx#a">ici</a>, vous trouverez également des informations pour la configuration des symboles sur <a href="http://www.microsoft.com/whdc/devtools/debugging/debugstart.mspx#a">cette page</a>.</p>
<p>Lançons Windbg en local kernel debugging (Cltrl K puis local). Dans l&rsquo;invite de commande, tapons :</p>
<pre>lkd&gt; rdmsr 174
msr[174] = 00000000`00000008
lkd&gt; rdmsr 176
msr[176] = 00000000`80541520</pre>
<p>Nous voyons donc que IA32_SYSENTER_CS = 0&#215;8 (donc avec un niveau de privilège à 0) et IA32_SYSENTER_EIP = 80541520. Au passage, on notera que cette adresse est supérieur à 80000000, c&rsquo;est à dire en mode noyau, puisque Windows divise l&rsquo;espace d&rsquo;adressage de tout processus en 2 : 2 Go pour l&rsquo;utilisateur (de 00000000 à 7FFFFFFF) et 2 Go pour le noyau (de 80000000 à FFFFFFFF). Regardons ce qui se trouve en 80541520 :</p>
<pre>lkd&gt; u 80541520 80541520+100     //desassemble les 100 premiers octets
nt!KiFastCallEntry:
80541520 b923000000      mov     ecx,23h
80541525 6a30            push    30h
80541527 0fa1            pop     fs
80541529 8ed9            mov     ds,cx
8054152b 8ec1            mov     es,cx
...
80541600 8b3f            mov     edi,dword ptr [edi]
80541602 8b1c87          mov     ebx,dword ptr [edi+eax*4]
80541605 2be1            sub     esp,ecx
80541607 c1e902          shr     ecx,2
8054160a 8bfc            mov     edi,esp
8054160c 3b3534215680    cmp     esi,dword ptr [nt!MmUserProbeAddress (80562134)]
80541612 0f83a8010000    jae     nt!KiSystemCallExit2+0x9f (805417c0)
80541618 f3a5            rep movs dword ptr es:[edi],dword ptr [esi]
8054161a ffd3            call    ebx</pre>
<p>On voit que la fonction s&rsquo;appelle <code>KiFastCallEntry</code> et se trouve dans le module nt qui correspond à ntoskrnl.exe, un des exécutables du noyau.</p>
<p>Après plusieurs vérifications de paramètres, la fonction <code>KiFastCallEntry</code> charge une table dans EDI (après les &laquo;&nbsp;&#8230;&nbsp;&raquo;). Il s&rsquo;agit de la SSDT (Service System Dispatch Table), une table très importante du noyau qui a un rôle similaire à la table d&rsquo;interruptions (IDT). Elle sert à dispatcher les appels systèmes vers la bonne fonction. Le symbole correspondant à la SSDT se nomme <code>KiServiceTable</code>, et est exporté par le noyau. Voici le début de son contenu :</p>
<pre>lkd&gt; dds KiServiceTable
80504450  805a4614 nt!NtAcceptConnectPort
80504454  805f0adc nt!NtAccessCheck
80504458  805f4312 nt!NtAccessCheckAndAuditAlarm
8050445c  805f0b0e nt!NtAccessCheckByType
80504460  805f434c nt!NtAccessCheckByTypeAndAuditAlarm</pre>
<p>Souvenez-vous : juste avant le SYSENTER, on a placé le numéro d&rsquo;appel système dans EAX. Ce registre va être utilisé ici afin de servir d&rsquo;index dans cette table et de trouver le pointeur de la fonction à appeler. L&rsquo;instruction suivante multiplie justement EAX par 4 (la taille d&rsquo;une entrée dans la table) et l&rsquo;ajoute à l&rsquo;adresse de début de la table contenu dans EDI. Le résultat est place dans EBX. Et quelques instructions plus loin, on trouve&#8230; un call EBX <img src='http://www.segmentationfault.fr/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Faisons le calcul nous même : nous connaissons le numéro d&rsquo;appel système (0&#215;74) :</p>
<pre>lkd&gt; dds KiServiceTable+0x74*4
80504620  8057a182 nt!NtOpenFile</pre>
<p>Bingo, voila la fonction <code>NtOpenFile</code> : c&rsquo;est elle qui sera exécutée lors du call EBX.</p>
<h3>Retour en userland</h3>
<p>Notre reversing peut s&rsquo;arrêter ici. Nous n&rsquo;allons pas désassembler cette fonction car ce n&rsquo;est pas le but de l&rsquo;article. Concernant le retour de l&rsquo;appel système, on peut, en désassemblant la suite de <code>KiFastCallEntry</code> , voir que la fonction <code>KiServiceExit</code> va être appelée. A son tour, elle appelle une des deux fonctions <code>KiSystemCallExit</code> ou <code>KiSystemCallExit</code>2. La première revient en mode utilisateur en utilisant l&rsquo;instruction IRET, et l&rsquo;autre le fait en utilisant SYSEXIT (c&rsquo;est celle là qui sera appelée dans notre cas). Cette instruction rebascule en userland et restaure EIP. On se retrouve alors dans <code>ZwOpenFile</code>, de ntdll.</p>
<h3>Conclusion</h3>
<p>Au travers de cet article, nous avons tracé l&rsquo;exécution d&rsquo;un programme utilisateur afin de comprendre comment il passe en mode noyau afin d&rsquo;exécuter des instructions privilégiées.  Nous avons vu comment fonctionne l&rsquo;instruction SYSENTER et le rôle de la SSDT.</p>
<p>On peut alors imaginer plusieurs hooks possibles exploitant ce schéma de fonctionnement. Au niveau utilisateur, on peut hooker l&rsquo;entrée de l&rsquo;IAT correspondant à la fonction à appeler. En mode noyau, il y a plusieurs possibilités. La première serait de remplacer l&rsquo;adresse de la fonction à appeler dans la SSDT par une autre fonction qui appelle l&rsquo;originale et effectue un filtrage en entrée et en sortie. Une autre serait de modifier carrément le registre IA32_SYSENTER_EIP en le faisant pointer sur une autre routine de traitement. L&rsquo;équivalent pour les vieilles versions de Windows utilisant les interruptions serait de modifier le registre IDTR contenant l&rsquo;adresse de la table des interruptions, ou bien de hooker l&rsquo;entrée 2E dans cette table. Enfin, une dernière solution, radicale mais fonctionnelle, serait de faire un hook inline de la fonction pointée, en remplaçant ses premiers octets par un call d&rsquo;une autre fonction. Comme vous le voyez, les possibilités de hook sont innombrables, les plus &laquo;&nbsp;profondes&nbsp;&raquo; étant bien souvent les plus indétectables&#8230;</p>
<h3>Références</h3>
<ul>
<li><a href="http://www.ivanlef0u.tuxfamily.org/?p=63">Ivanlef0u&rsquo;s Blog &#8211; SSDT Hooking Reinvented</a></li>
<li><a href="http://www.ivanlef0u.tuxfamily.org/?p=22">Ivanlef0u&rsquo;s Blog &#8211; SYSENTER, stepping into da ring0</a></li>
<li><a href="http://www.amazon.com/Rootkits-Subverting-Addison-Wesley-Software-Security/dp/0321294319">Rootkits &#8211; Subverting the Windows Kernel, Greg Hoglund et Jamie Butler<br />
</a></li>
<li><a href="http://download.intel.com/design/processor/manuals/253668.pdf">Intel 64 and IA-32 Architectures Software Developer’s Manual, Volume 2B</a>, Chapitre 4.1, Instruction SYSENTER</li>
<li><a href="http://download.intel.com/design/processor/manuals/253668.pdf">Intel 64 and IA-32 Architectures Software Developer’s Manual, Volume 3A</a>, Chapitre 4.5</li>
<li><a href="http://www.microsoft.com/whdc/devtools/debugging/installx86.mspx#a">Debugging Tools for Windows</a></li>
<li><a href="http://www.microsoft.com/whdc/devtools/debugging/debugstart.mspx#a">Debugging Tools and Symbols: Getting Started</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.segmentationfault.fr/reversing/plongeon-dans-les-appels-systemes-windows/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Stage chez Thomson R&amp;D</title>
		<link>http://www.segmentationfault.fr/projets/stage-chez-thomson-rd/</link>
		<comments>http://www.segmentationfault.fr/projets/stage-chez-thomson-rd/#comments</comments>
		<pubDate>Wed, 25 Mar 2009 14:48:10 +0000</pubDate>
		<dc:creator>Emilien Girault</dc:creator>
				<category><![CDATA[Projets]]></category>
		<category><![CDATA[Reverse Engineering]]></category>
		<category><![CDATA[ring 0]]></category>

		<guid isPermaLink="false">http://www.segmentationfault.fr/?p=587</guid>
		<description><![CDATA[J&#8217;ai commencé mon stage il y a maintenant une dizaine de jours chez Thomson R&#38;D à Cesson-Sévigné. Comme prévu, mon stage a pour sujets principaux le reverse-engineering et le développement de drivers.  Pour être plus précis, le but du stage est de réaliser un conteneur sécurisé de données. Autrement dit, un module qui va contenir [...]]]></description>
			<content:encoded><![CDATA[<p>J&rsquo;ai commencé mon stage il y a maintenant une dizaine de jours chez Thomson R&amp;D à Cesson-Sévigné. Comme prévu, mon stage a pour sujets principaux le reverse-engineering et le développement de drivers.  Pour être plus précis, le but du stage est de réaliser un conteneur sécurisé de données. Autrement dit, un module qui va contenir des données très sensibles et dont le but va être de les rendre inaccessibles de l&rsquo;extérieur. Il s&rsquo;agit d&rsquo;un projet purement orienté recherche, et à part mon maître de stage, je suis seul à travailler dessus.<span id="more-587"></span></p>
<p>Au programme : plongeon dans les bas fonds de l&rsquo;architecture x86 d&rsquo;Intel, et plus précisément toutes les fonctionnalités de protection, dont certaines sont parfois méconnues (ou pas). Ce n&rsquo;est pas sans me rappeler certaines parties de mes cours de système suivis à l&rsquo;INSA et au RIT, mais avec une forte dose de concret en plus&#8230;</p>
<p>Cette fois-ci, une grosse partie du code s&rsquo;exécutera en mode noyau (ring 0), ce qui va me faire goûter aux joies de la programmation de drivers et des <em>Blue Screen Of Death</em> de Windows. D&rsquo;ailleurs au niveau de l&rsquo;OS, je travaille principalement Windows pour le moment, mais dans l&rsquo;idéal, le projet devrait aussi être porté sous Linux.</p>
<p>De plus, qui dit sécurité des données et confidentialité dit&#8230; cryptographie ! Le module que je vais développer devra intégrer des primitives de base permettant d&rsquo;encrypter les données sensibles et de les décrypter au moment voulu.</p>
<p>Enfin, ce stage va être l&rsquo;occasion pour moi de redécouvrir les techniques utilisées par les rootkits, principalement le hooking et la furtivité. Autant dire que je me sens comme un poisson dans l&rsquo;eau&#8230;</p>
<p>Bien entendu, ayant signé une charte de confidentialité, je ne pourrais pas divulguer tout ce que je fais dans les moindres détails, mais je compte bien publier ici quelques articles concernant des sujets ou projets du domaine public que mon stage m&rsquo;aura fait découvrir.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.segmentationfault.fr/projets/stage-chez-thomson-rd/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>InjecSO : Injection de .so sous Linux</title>
		<link>http://www.segmentationfault.fr/projets/injecso-injection-de-so-sous-linux/</link>
		<comments>http://www.segmentationfault.fr/projets/injecso-injection-de-so-sous-linux/#comments</comments>
		<pubDate>Sat, 14 Feb 2009 20:37:52 +0000</pubDate>
		<dc:creator>Emilien Girault</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Projets]]></category>
		<category><![CDATA[Reverse Engineering]]></category>
		<category><![CDATA[Sécurité informatique]]></category>
		<category><![CDATA[hacking]]></category>

		<guid isPermaLink="false">http://www.segmentationfault.fr/?p=521</guid>
		<description><![CDATA[L&#8217;injection de librairie dynamique est une technique principalement orientée reverse-engineering qui consiste à introduire et exécuter du code dans un processus actif du système d&#8217;exploitation. Le code en question s&#8217;exécute alors dans le contexte du processus cible, et peut accéder aux mêmes ressources. Attention, je parle bien d&#8217;injection dynamique, c&#8217;est à dire qu&#8217;elle peut avoir [...]]]></description>
			<content:encoded><![CDATA[<p>L&rsquo;injection de librairie dynamique est une technique principalement orientée reverse-engineering qui consiste à introduire et exécuter du code dans un processus actif du système d&rsquo;exploitation. Le code en question s&rsquo;exécute alors dans le contexte du processus cible, et peut accéder aux mêmes ressources. Attention, je parle bien d&rsquo;injection dynamique, c&rsquo;est à dire qu&rsquo;elle peut avoir lieu n&rsquo;importe quand après le lancement du processus, et non pas juste à son lancement comme avec la technique utilisant <code>LD_PRELOAD</code> (qui en plus ne fonctionne pas avec les programmes setuid).</p>
<p>Après avoir lu de nombreux articles sur l&rsquo;injection de DLL sous Windows, j&rsquo;ai commencé à en avoir assez à ne pas trouver d&rsquo;équivalent sous Linux.  Le peu d&rsquo;information que j&rsquo;ai trouvé pour Linux datent d&rsquo;au moins 5 ans, et se révèlent non adaptables aux distributions récentes. C&rsquo;est pourquoi je me suis lancé dans l&rsquo;idée de réaliser ce genre d&rsquo;outil moi même. Ainsi, après m&rsquo;être heurté à plusieurs obstacles, j&rsquo;ai finalement réussi à développer un outil fonctionnel : <strong>InjecSO</strong>. <span id="more-521"></span></p>
<p>Cet outil marche très bien sur ma machine qui est une Ubuntu 8.10, avec un noyau 2.6.27, sans outil de protection de la mémoire comme PaX (la technique utilisée ne marchera pas si la pile n&rsquo;est pas exécutable), et avec une Libc de version 2.8.90. Je n&rsquo;ai pas eu l&rsquo;occasion de tester sur d&rsquo;autres machines, mais je pense qu&rsquo;il devrait fonctionner aussi bien, les deux seuls obstacles étant l&rsquo;implémentation de la librairie standard et les éventuels patches appliqués au noyau.</p>
<h3>InjecSO in a nutshell</h3>
<p>Voyons dans un premier temps comment utiliser InjecSO dans un cas simple.</p>
<h4>Téléchargement</h4>
<p><a href="http://www.segmentationfault.fr/wp-content/uploads/2009/02/injecso-1-0tar.gz">Télécharger InjecSO au format tar.gz</a></p>
<h4>Présentation rapide</h4>
<p>InjecSO se présente sous la forme de deux outils.</p>
<ul>
<li><code>injecso</code> est le cœur du programme utilisé pour l&rsquo;injection de code. Il s&rsquo;agit d&rsquo;un programme écrit en C qui prend 3 arguments : le pid du processus cible, le chemin absolu de la librairie à injecter, et l&rsquo;adresse de la fonction <code>__libc_dlopen_mode()</code> dans l&rsquo;espace mémoire du processus cible. Cette dernière est une fonction spéciale de la libc qui rend l&rsquo;injection possible et est décrite précisément dans la deuxième partie de l&rsquo;article. Localiser cette adresse précise dans le processus cible est faisable mais rébarbatif ; c&rsquo;est pourquoi j&rsquo;ai développé un deuxième outil pour se faciliter la vie.</li>
<li><code>injecso.sh</code> est un script Bash qui a justement pour but de calculer cette adresse de façon automatique. Il ne prend donc que deux paramètres : le pid et le nom de la librairie à injecter. Il appelle automatiquement le programme précédent en lui fournissant le paramètre manquant. De plus, le chemin de la librairie peut être relatif car l&rsquo;outil calcule le chemin absolu automatiquement.</li>
</ul>
<p>J&rsquo;entends déjà des remarques venir :  «Pourquoi ne pas avoir tout intégré dans un seul programme ?». La réponse est simple : cela aurait été faisable, mais m&rsquo;aurait nécessité beaucoup plus de temps pour au final arriver au même résultat. Le calcul de l&rsquo;adresse nécessite d&rsquo;analyser la mémoire du processus et le code de la libc, et il se trouve qu&rsquo;il existe déjà des outils qui font cela très bien sous Linux. Ainsi, <code>injecso.sh</code> ne fait qu&rsquo;exploiter ces ressources pour calculer rapidement l&rsquo;adresse de la fonction voulue. Je suis conscient que cela a ses avantages et ses inconvénients ; en particulier, le script nécessite que vous ayez certaines dépendances d&rsquo;installées, dont <code>readelf</code> et <code>perl</code> (pour parser la sortie produite par ces outils). Je ne pense pas que cela soit une exigence trop forte, puisque ces outils sont en général présents sur beaucoup de systèmes, et sont au pire facilement installables surtout si votre distribution comprend un système de paquets.</p>
<h4>Compiler le programme</h4>
<p>Décompressez l&rsquo;archive et utilisez le Makefile pour compiler l&rsquo;exécutable :</p>
<pre>$ tar xzvf injecso-1.0tar.gz
$ make</pre>
<h4>Exemples d&rsquo;utilisation</h4>
<p>L&rsquo;outil est capable d&rsquo;injecter n&rsquo;importe quelle librairie dans n&rsquo;importe quel type de processus, pour peu que vous ayez les droits suffisants (n&rsquo;espérez pas injecter du code dans un processus appartenant à root si vous ne l&rsquo;êtes pas vous-même). Comme exemple, prenons un processus simple tel que l&rsquo;éditeur de texte <code>vi</code> et une librairie dynamique qui affiche &laquo;&nbsp;Hello World!&nbsp;&raquo; nommée <code>libhelloworld.so</code>. Voici le code de <code>libhelloworld.c</code> :</p>
<pre>#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;

void __attribute__ ((constructor)) hello_world(void);

void hello_world(void){
  printf("Hello World!n");
}</pre>
<p>La directive <code>__attribute__ ((constructor))</code> indique au compilateur qu&rsquo;il devra ajouter cette fonction à la liste des fonctions à appeler au chargement de la libairie. Si vous êtes familier du monde Windows, c&rsquo;est plus ou moins l&rsquo;équivalent de la directive <code>DllMain()</code>. Compilez le code avec :</p>
<pre>$ gcc libhelloworld.c -o libhelloworld.so -shared -fPIC</pre>
<p>Vous pouvez placer cette librairie ou bon vous semble, le plus simple étant de la mettre dans le même dossier qu&rsquo;InjectSO. Lancez <code>vi</code>, récupérez son pid avec la commande <code>pidof vi</code> et lancez l&rsquo;injection !</p>
<pre>$ ./injecso.sh $(pidof vi) ./libhelloworld.so
[+] Found __libc_dlopen_mode at 0xb7e44210
[+] Launching: injecso 9796 libhelloworld.so 0xb7e44210
[+] Attaching...
[+] Waiting for process...
[+] Copying shellcode to 0xbfa0b02e...
[+] Setting eip and esp...
[+] Detaching...</pre>
<p>Regardez à présent la fenête où vous avez lancez <code>vi</code>&#8230; Vous devriez voir un petit <code>Hello World!</code> en haut de la console <img src='http://www.segmentationfault.fr/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Vous pouvez aussi bien injecter votre librairie dans des plus gros processus comme par exemple Firefox — pour les applications graphiques, le message s&rsquo;affichera dans la console ayant l&rsquo;ancé le programme —, et complexifier votre librairie. Les possibilités n&rsquo;ont de limite que votre imagination : création d&rsquo;un client ou serveur, dump de la mémoire, log d&rsquo;événements, hooking de fonctions de la PLT&#8230; Notez que votre librairie peut à son tour appeler d&rsquo;autres librairies (dynamiques ou pas) sans aucun problème.</p>
<h4>Remarque concernant les threads</h4>
<p>Il est important de noter qu&rsquo;InjecSO ne crée aucun thread dans le processus cible. A la différence des outils d&rsquo;injection de code sous Windows qui effectuent un appel à <code>CreateRemoteThread()</code>, le code injecté est directement exécuté dans le contexte courant du processus, qui est sauvegardé avant l&rsquo;injection puis restauré. Si le code de votre librairie est gros ou effectue des opérations gourmandes en cycles CPU, le processus cible en sera ralenti. Cette remarque &lsquo;est particulièrement valable si votre librairie effectue des entrées/sorties disque ou réseau (si vous comptez coder un serveur&#8230;). C&rsquo;est pourquoi dans ces cas il est préférable de créer un nouveau thread, en utilisant par exemple la libairie <code>pthread</code>.</p>
<h3>Détails d&rsquo;implémentation</h3>
<p>Cette section décrit en détails comment InjecSO est implementé. Je commence par faire un tour d&rsquo;horizon des techniques utilisées, puis je détaille le code de l&rsquo;outil.</p>
<h4>ptrace() et dlopen()</h4>
<p>Il faut reconnaître que sous Linux, l&rsquo;attirail disponible pour injecter des librairies est très limité, en tout cas beaucoup plus que sous Windows. A vrai dire, il n&rsquo;y a tout simplement pas d&rsquo;appel de fonction tel que  <code>OpenProcess()</code> et <code>CreateRemoteThread()</code>, donc manipuler un processus devient beaucoup plus délicat. Le seul outil dont nous disposons est <code>ptrace()</code>.  Il s&rsquo;agit d&rsquo;un appel système qui est utilisé majoritairement pour le débogage de processus. Il est relativement simple à utiliser ; on commence par s&rsquo;attacher au processus à tracer, qui se bloque. On peut alors récupérer son état, ses registres et sa mémoire d&rsquo;un processus, et les modifier. Une fois les opérations de tracage terminées, on se détache, et le processus reprend son cours. Nous allons voir comment InjecSO utilise cet appel système par la suite ; en attendant je vous renvoie au manuel si vous voulez en savoir plus.</p>
<p>Pour charger une librairie dynamique sous Unix, on utilise la fonction <code>dlopen()</code> qui est plus ou moins l&rsquo;équivalent de <code>LoadLibraryA()</code> sous Windows. Cette fonction prend en paramètre le nom de la librairie à charger, ainsi qu&rsquo;un flag qui indique la manière dont doivent être résolus les symboles. Cela n&rsquo;a guère d&rsquo;importance pour notre application, aussi nous spécifierons arbitrairement que les symboles doivent tous être résolus au chargement.</p>
<h4>Un premier problème : dlopen()</h4>
<p>A première vue, <code>ptrace()</code> et <code>dlopen()</code> constituent de bonnes bases pour notre injection. Seulement, ce n&rsquo;est pas si simple : il se trouve que la fonction <code>dlopen()</code> n&rsquo;est pas une fonction standard, mais se situe dans une librairie séparée nommée <code>libdl</code>&#8230; qui n&rsquo;est pas toujours chargée par tous les processus. Autrement dit, un processus lambda ne possède pas forcément le moyen de charger une librairie dynamique, car la fonction qui permet de charger des librairies se trouve justement dans une librairie dynamique !</p>
<p>C&rsquo;est là qu&rsquo;on peut se dire «OK, mais alors comment fait un processus quand il veut charger une librairie ?». Réponse : c&rsquo;est le programmeur qui spécifie au moment de la compilation et de l&rsquo;édition des liens qu&rsquo;il vaut lier son programme avec <code>libdl</code> qui sera alors chargée à son lancement. Sauf que dans notre cas, nous ne sommes pas forcément le développeur du programme cible, et nous ne voulons de toute manière pas modifier le code du programme&#8230;</p>
<h4>La solution : __libc_dlopen_mode()</h4>
<p>En cherchant de la documentation sur les détails d&rsquo;implémentation de <code>dlopen()</code>, j&rsquo;ai finalement trouvé un papier datant de 2003 [1] qui explique que les fonctions de <code>libdl</code> sont pour la plupart des <em>stubs</em> qui appellent des fonctions qui se trouvent en réalité dans la libc. Rappelons que la libc est chargée dans quasiment tous les processus, donc cette découverte parraît très intéressante. Selon le papier, <code>dlopen()</code> appelle en fait <code>_dl_open()</code>. Après vérification, je me rend compte que ce n&rsquo;est pas/plus le cas, du moins sur ma machine. Mais il semblerait qu&rsquo;il y ait une fonction similaire avec un nom assez proche :  <code>__libc_dlopen_mode()</code>. Voici la mise en évidence en images :</p>
<pre>$ pidof bash
10712 9864 8911
$ cat /proc/10712/maps | grep libc
b7d61000-b7eb9000 r-xp 00000000 08:08 51577   /lib/tls/i686/cmov/libc-2.8.90.so
b7eb9000-b7ebb000 r--p 00158000 08:08 51577   /lib/tls/i686/cmov/libc-2.8.90.so
b7ebb000-b7ebc000 rw-p 0015a000 08:08 51577   /lib/tls/i686/cmov/libc-2.8.90.so
$ readelf -s -D /lib/tls/i686/cmov/libc-2.8.90.so | grep dlopen
 2188 744: 0011d210   156    FUNC GLOBAL DEFAULT  11 __libc_dlopen_mode
 2188 966: 0011d210   156    FUNC GLOBAL DEFAULT  11 __libc_dlopen_mode</pre>
<p>Dans un premier temps, on récupère les pid d&rsquo;un processus quelconque, ici Bash, on obtient le chemin complet de la libc (ici <code>/lib/tls/i686/cmov/libc-2.8.90.so</code>) et on utilise <code>readelf</code> pour afficher les symboles dynamiques de la librairie. Résultat : il y a bien une fonction qui a l&rsquo;air similaire à <code>dlopen()</code>.</p>
<p>Mais que fait cette fonction, et quel est son prototype ? Pour cela, le plus simple est de récupérer le code source de la librairie standard et de le parcourir. C&rsquo;est ce que j&rsquo;ai donc fait, et je suis finalement tombé sur cela :</p>
<pre>extern void *__libc_dlopen_mode  (__const char *__name, int __mode);</pre>
<p>Comparons cela au prototype original de <code>dlopen()</code> :</p>
<pre>void *dlopen(const char *filename, int flag);</pre>
<p>Hum&#8230; cela paraît très similaire, pour ne pas dire identique ! Je m&rsquo;empresse donc de coder un petit programme en C qui appelle cette fonction, et m&rsquo;aperçois alors que la libraire est bien chargée, comme avec <code>dlopen()</code> ! Super, nous pouvons donc nous contenter de cette fonction.</p>
<h4>Deuxième problème : randomization des adresses</h4>
<p>Ok, nous avons maintenant un nom de fonction pour charger la librairie. Cependant, pour pouvoir l&rsquo;appeler dans le processus cible, il nous faut son adresse. Comment l&rsquo;obtenir, sachant qu&rsquo;elle se trouve dans l&rsquo;espace mémoire du processus cible ? Nous savons que la fonction réside dans la libc ; pour déterminer son adresse nous pouvons utiliser le même programme que précédamment, <code>readelf</code>. Lors de notre dernière commande, cet outil nous a indiqué que la fonction se situe à l&rsquo;offset <code>0x0011d210</code> dans l&rsquo;image mémoire de la librairie. Comment obtenir l&rsquo;adresse globale à partir de cet offset ? Simplement en additionnant cet offset avec l&rsquo;adresse de base à laquelle est chargée la libc. Mais quelle est l&rsquo;adresse de base de la libc ? Observons le résultat de la commande <code>ldd</code> :</p>
<pre>$ ldd /bin/bash | grep libc
        libc.so.6 =&gt; /lib/tls/i686/cmov/libc.so.6 (0xb7ee4000)</pre>
<p>Nous utilisons cette commande sur Bash, et filtrons la sortie pour n&rsquo;afficher que ce qui nous intéresse. Notez que le chemin de la libc est ici différent de précédamment, mais cela n&rsquo;a pas d&rsquo;importance pour ce que je cherche à illustrer ici.  Ce qu&rsquo;il faut noter ici, c&rsquo;est que <code>ldd</code> nous affiche que la libc est chargée à l&rsquo;adresse <code>0xb7ee4000</code>. Mais il y a un léger hic&#8230; En effet, si on relance la même commande une deuxième fois&#8230;</p>
<pre>$ ldd /bin/bash | grep libc
        libc.so.6 =&gt; /lib/tls/i686/cmov/libc.so.6 (0xb7ef0000)</pre>
<p>Oups. L&rsquo;adresse a changée ! Pourquoi donc ? Parce que depuis relativement récamment (quelques années), Linux a introduit un système de randomization des adresses. Autrement dit, l&rsquo;adresse à laquelle une librairie est chargée n&rsquo;est pas constante et varie pour toutes les exécutions d&rsquo;un programme donné. Autant dire que cela ne va pas nous faciliter la tâche pour calculer l&rsquo;adresse de  <code>__libc_dlopen_mode()</code>&#8230;</p>
<h4>Solution : /proc/&lt;pid&gt;/maps</h4>
<p>Tout n&rsquo;est pas perdu. Linux possède un système de fichier virtuel, nommé <code>/proc/</code>, qui va nous permettre de nous en sortir. En effet, lorsqu&rsquo;un processus est créé, Linux crée un répertoire <code>/proc/&lt;pid&gt;/</code> (<code>&lt;pid</code>&gt; étant le nom du processus en question) contenant plein d&rsquo;informations. En particulier, le fichier <code>/proc/&lt;pid&gt;/maps</code> contient la liste de toutes les sections mappées mémoires dans l&rsquo;espace du processus. Voyons ce que nous pouvons obtenir&#8230;</p>
<pre>$ pidof bash
10712 9864 8911
$ cat /proc/10712/maps | grep libc
b7d61000-b7eb9000 r-xp 00000000 08:08 51577  /lib/tls/i686/cmov/libc-2.8.90.so
b7eb9000-b7ebb000 r--p 00158000 08:08 51577  /lib/tls/i686/cmov/libc-2.8.90.so
b7ebb000-b7ebc000 rw-p 0015a000 08:08 51577  /lib/tls/i686/cmov/libc-2.8.90.so</pre>
<p>On s&rsquo;aperçoit que la libc est mappée 3 fois dans l&rsquo;espace mémoire de Bash : une fois en lecture et exécution, une fois en lecture seule, et une fois en lecture et écriture. En ce qui nous concerne, nous souhaitons exécuter une fonction, donc nous avons intérêt à choisir la section exécutable. Son adresse est <code>0xb7d61000</code> ; ajoutons à cela l&rsquo;offset précédent (<code>0x0011d210</code>), et nous obtenons l&rsquo;adresse de <code>__libc_dlopen_mode()</code> ! Sa valeur n&rsquo;a pas d&rsquo;importance dans cet exemple car nous voulons juste un moyen de la calculer automatiquement pour n&rsquo;importe quel processus.</p>
<h3>Injecso.sh : calcul de l&rsquo;adresse</h3>
<p>Si nous rassemblons tout ce que nous venons de voir, nous savons désormais calculer l&rsquo;adresse de <code>__libc_dlopen_mode()</code> pour un processus donnée. Il ne reste plus qu&rsquo;à mettre tout cela dans un script ; c&rsquo;est le but d&rsquo;<code>injecso.sh</code>. Le script a volontairement été raccourci ici pour n&rsquo;afficher que les bouts intéressants.</p>
<pre>#!/bin/bash
# Param renaming
pid=$1
lib=$2</pre>
<p>Nous commençons par récupérer la ligne de <code>/proc/&lt;pid&gt;/maps</code> qui nous intéresse, et nous allons extraire d&rsquo;une part l&rsquo;adresse de base de la librairie, et son nom.</p>
<pre># Get the map of process and get the line
# that correspond to the executable section of libc
line=$(cat /proc/$pid/maps | grep "libcb" | grep r-x | head -n 1)</pre>
<pre># Extract the base address of that section and the name of the library
libc_baseaddr=$(echo "$line" | cut -d "-" -f1)                # first field
libc_name=$(echo "$line" | perl -n -e '/(S+$)/ &amp;&amp; print $1') # last field</pre>
<p>Nous utilisons ensuite <code>readelf </code>pour extraire l&rsquo;offset de <code>__libc_dlopen_mode()</code>.</p>
<pre># Use readelf to find the offset of __libc_dlopen_mode
dlopen_offset=$(readelf -s -D $libc_name | grep __libc_dlopen_mode |
  head -n 1 | perl -n -e '/^s*S+s+S+s+(S+)/ &amp;&amp; print $1') # 3rd field</pre>
<p>L&rsquo;adresse est obtenue en additionnant cet offset avec l&rsquo;adresse de base.</p>
<pre># Compute the actual addresses
dlopen_addr=$(expr $(printf "%d" 0x$libc_baseaddr) 
  + $(printf "%d" 0x$dlopen_offset))
dlopen_addr_hex=$(printf "0x%x" $dlopen_addr)

echo "[+] Found __libc_dlopen_mode at $dlopen_addr_hex"
echo "[+] Launching: injecso $pid $lib $dlopen_addr_hex"</pre>
<p>Il ne reste plus qu&rsquo;a passer les paramètres adéquats à notre injecteur.</p>
<pre># Launch InjecSO
$(dirname $0)/injecso $pid $(pwd)/$lib $dlopen_addr_hex</pre>
<p>Voila, nous venons de faire le tour du script. Plutôt simple, la difficulté majeure étant de parser la sortie des différents outils utilisés.</p>
<h4>Structure de l&rsquo;injection</h4>
<p>Bon, ce n&rsquo;est pas tout, mais nous n&rsquo;avons toujours pas vu comment se déroule l&rsquo;injection ! C&rsquo;est là que nous allons utiliser <code>ptrace()</code>&#8230; Comme je l&rsquo;ai dit précédemment, cet appel système permet de modifier la mémoire et les registres d&rsquo;un processus cible. Comment l&rsquo;utiliser à fin d&rsquo;injecter un appel à <code>__libc_dlopen_mode()</code> ? La solution la plus simple est d&rsquo;injecter un shellcode qui va réaliser l&rsquo;appel. Il y a plusieurs possibilités pour ce faire ; j&rsquo;ai choisi la plus simple c&rsquo;est à dire d&rsquo;injecter le shellcode dans la pile. Notez que cela requirt que la pile soit exécutable, ce qui n&rsquo;est pas toujours le cas.</p>
<p>De plus, il va nous falloir faire très attention car nous ne voulons pas crasher le processus cible. Comme notre shellcode sera susceptible de s&rsquo;exécuter n&rsquo;importe quand dans le processus, il doit rester &laquo;&nbsp;invisible&nbsp;&raquo;. Autrement dit, il faut que l&rsquo;état du processeur avant et après l&rsquo;exécution du shellcode soit &laquo;&nbsp;quasiment&nbsp;&raquo; le même. Pour cela, nous allons devoir sauvegarder les registres avant d&rsquo;exécuter la charge utile du shellcode, et les restaurer ensuite.</p>
<p>Là encore, il y a plusieurs solutions pour résoudre ce problème ; je vais détailler celle que j&rsquo;ai retenue pour injecSO. Voici un shema de la pile avant l&rsquo;appel au shellcode :</p>
<pre> |               |
 |               |
 |               |
 |               |
 |               |
 +---------------+
 |    donnees    | &lt;- esp
 |               |</pre>
<p>Dans ce schéma, les adresses croissent vers le bas, mais rappelez-vous que la pile croît en sens inverse. Au moment de l&rsquo;injection, nous allons effectuer les opérations suivantes en utilisant <code>ptrace()</code>:</p>
<ul>
<li>Sauvegarder l&rsquo;adresse de l&rsquo;instruction courante (contenue dans <code>eip</code>) sur la pile</li>
<li>Allouer le shellcode sur la pile</li>
<li>Faire pointer  <code>eip </code>et <code>esp</code> sur le shellcode</li>
</ul>
<p>Voici donc la pile après l&rsquo;injection :</p>
<pre> |               |
 +---------------+
 |   shellcode   | &lt;- eip, esp
 |               |
 |               |
 |               |
 +---------------+
 |  ancien eip   |
 +---------------+
 |    donnees    |
 |               |</pre>
<p>Pour que cela fonctionne, le shellcode devra avoir une structure particulière :</p>
<ul>
<li>Quelques <code>nops</code> afin de compenser un éventuel décalage dans les adresses.</li>
<li><code>pushal</code> afin de sauvegarder les registres sur la pile.</li>
<li>Charge utile du shellcode (en gros, <code>push</code> des arguments et <code>call</code><code> __libc_dlopen_mode</code> )</li>
<li><code>popal</code> pour restaurer les registres</li>
<li><code>addl $size, %esp</code> (<code>$size</code> étant la taille du shellcode) afin de repositionner <code>esp</code> sur l&rsquo;adresse de retour</li>
<li><code>ret</code> qui dépilera et restaurera l&rsquo;adresse de retour</li>
</ul>
<p>L&rsquo;injecteur va dans un premier temps générer le shellcode suivant ce modèle. Cependant, ce modèle est incomplet car le shellcode nécessite des paramètres qui ne seront connus qu&rsquo;à l&rsquo;exécution : l&rsquo;adresse de <code>__libc_dlopen_mode</code>, le nom de la librairie à injecter, ainsi que la taille du shellcode (comprenant le nom de la librairie). Ainsi, l&rsquo;injecteur va devoir compléter/patcher le shellcode à plusieurs endroits avant qu&rsquo;il soit fonctionnel.</p>
<h4>Le shellcode</h4>
<p>Voici le code du shellcode utilisé ; je pense que les commentaires sont assez explicites :</p>
<pre>  .text
  .globl shellcode_code
  .globl shellcode_code_end

shellcode_code:

  /* Some nops */
  nop
  nop
  nop
  nop
  nop
  nop
  nop

  /* Save all registers */
  pushal

  /* Get the name of the library into ebx */
  jmp       libname

call_dlopen:
  popl      %ebx

  /* 0x11111111 will be later replaced by
     the address of __lib_dlopen_mode */
  movl      $0x11111111, %eax
  pushl     $2      /* RTLD_NOW */
  pushl     %ebx    /* name of the library */
  call      *%eax   /* call __lib_dlopen_mode */

  /* Clean args on the stack */
  addl      $8, %esp

  /* Restore all registers */
  popal

  /* 0x12345678 will be later replaced by
     the size of the shellcode (+ delta) */
  addl      $0x12345678, %esp

  /* Return to where we were before */
  ret

libname:
  call call_dlopen
shellcode_code_end:
/*
 * End of shellcode
 * The string corresponding to the library name
 * will be put here later
 */</pre>
<p>Comme je le disais, le shellcode est encore incomplet. En particulier, il manque encore le nom de la librairie, qui sera ajouté à la fin. Pour récupérer son adresse relative, nous utilisons l&rsquo;astuce du <code>jmp/call</code>, assez célèbre. Concernant l&rsquo;adresse de  <code>__libc_dlopen_mode</code> et la taille du shellcode, nous laissons des offsets bidon pour le moment que nous allons patcher ensuite. Voila justement le début du code de l&rsquo;injecteur, qui a pour but d&rsquo;assembler/patcher le shellcode :</p>
<pre>int main(int argc, char **argv){
  char * shellcode;
  int shellcode_size, libname_size;
  char * ptr;
  int i;
  int pid;
  char * libname;
  int dlopen_addr;

  //Check parameters
  check_params(argc, argv, &amp;pid, &amp;libname, &amp;dlopen_addr);</pre>
<p>Ici, nous venons de récupérer les paramètres de l&rsquo;injecteur, c&rsquo;est à dire le pid, le nom de la librairie et l&rsquo;adresse de <code>__libc_dlopen_mode</code>. Je ne pense pas que cette fonction soit sufisamment intéressante et complexe pour être détaillée ici.</p>
<pre>  //Compute the size of the library name and deduce the shellcode size
  libname_size = strlen(libname);
  shellcode_size = (char *) shellcode_code_end - (char *) shellcode_code 
                   + libname_size + 1;

  //Allocate the shellcode buffer
  shellcode = malloc(shellcode_size);</pre>
<p>La copie du shellcode commence ici, puis le nom de la librairie y est ajouté.</p>
<pre>  //Copy the shellcode code into the buffer
  for(i = 0, ptr = (char *) shellcode_code;
      ptr != (char *) shellcode_code_end;
      ptr++, i++){
    shellcode[i] = *ptr;
  }

  //Copy the library name at the end of the shellcode
  for(ptr = libname; *ptr != 0; ptr++, i++){
    shellcode[i] = *ptr;
  }</pre>
<p>Maintenant, c&rsquo;est le moment de patcher le shellcode. Le début du shellcode ayant une taille fixe, nous connaissons précisément les offsets à patcher (il suffit d&rsquo;assembler le shellcode une première fois et de compter).</p>
<pre>  //Patch the shellcode by inserting the real address of __libc_dlopen_mode
  //(replace 0x11111111 by dlopen_addr)
  *((int *) &amp;(shellcode[12])) = dlopen_addr;

  //Patch the shellcode to include its own size
  *((int *) &amp;(shellcode[27])) = shellcode_size + DELTA_SHELLCODE_EIP_BAK;</pre>
<p>Il y a un petit détail dont je n&rsquo;ai pas parlé : l&rsquo;expérience montre que le shellcode inséré tel quel juste après l&rsquo;adresse de retour ne marche pas ; la fin du shellcode se retrouve écrasée pour une raison que je n&rsquo;ai pas encore bien comprise. Pour éviter ça, j&rsquo;ai introduit une petit décalage (delta) de quelques octets entre l&rsquo;adresse de retour et la fin du shellcode, afin de garantir qu&rsquo;elle ne sera pas touchée. Il faut juste prendre en compte ce décalage dans certains calculs, bref rien de très compliqué.</p>
<pre>  //Inject!
  inject(pid, shellcode, shellcode_size);</pre>
<p>Le shellcode est désormais prêt, place à l&rsquo;injection !</p>
<h4>L&rsquo;injection de code</h4>
<p>Voici enfin la routine qui effectue l&rsquo;injection.</p>
<pre>void inject(int pid, char * shellcode, int shellcode_size){

  long res;
  struct user_regs_struct regs;
  char * addr_shellcode;
  int i;

  //Attach to the process
  printf("[+] Attaching...n");
  res = ptrace(PTRACE_ATTACH, pid, NULL, NULL);
  if(res == -1){
    perror("Attaching");
  }</pre>
<p>Après s&rsquo;être attaché au processus, il faut impérativement l&rsquo;attendre, sans quoi il risque de ne pas être prêt.</p>
<pre>  //Wait for the process
  printf("[+] Waiting for process...n");
  waitpid(pid, NULL, 0);

  //Set option for interrupted syscalls
  res = ptrace(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_TRACESYSGOOD);
  if(res == -1){
    perror("Setting ptrace option");
  }</pre>
<p>Cette option n&rsquo;est pas obligatoire, mais est préférable dans le cas où le processus a été interompu en plein milieu d&rsquo;un appel système.</p>
<pre>  //Get the registers of the process
  res = ptrace(PTRACE_GETREGS, pid, NULL, &amp;regs);
  if(res == -1){
    perror("Getting registers");
  }</pre>
<p>Nous avons les registres du processus, nous pouvons maintenant les manipuler comme nous voulons. Nous commençons par calculer l&rsquo;adresse à laquelle le shellcode devra être chargé, puis nous sauvegardons l&rsquo;adresse de retour sur la pile</p>
<pre>  //Compute the address where the shellcode will be copied
  //We keep 4 bytes for old eip and a delta between this
  //and the end of the shellcode
  addr_shellcode = (char *) regs.esp - shellcode_size 
                    - DELTA_SHELLCODE_EIP_BAK - 4;

  //Save eip on the stack (esp orig - 4)
  res = ptrace(PTRACE_POKEDATA, pid, regs.esp-4, regs.eip);
  if(res == -1){
    perror("Saving eip");
  }</pre>
<p>Il faut maintenant copier le shellcode. Attention : lors des transferts de données, <code>ptrace()</code> copie les octets 4 par 4. Il faut donc faire attention lors de l&rsquo;itération, et ne pas oublier la fin du shellcode.</p>
<pre>  //Copy shellcode
  printf("[+] Copying shellcode to 0x%x...n", (int) addr_shellcode);
  for(i = 0; i &lt; shellcode_size/4; i++){
    res = ptrace(PTRACE_POKEDATA, pid, &amp;addr_shellcode[i*4], 
         (int) *((int*) &amp;shellcode[i*4])); //Copy 4 bytes each time
    if(res == -1){
      perror("Copying shellcode");
    }
  }
  if((shellcode_size % 4) != 0){
    res = ptrace(PTRACE_POKEDATA, pid, &amp;addr_shellcode[i*4], 
         (int) *((int*) &amp;shellcode[i*4])); //Copy the last 3- bytes if necessary
    if(res == -1){
      perror("Copying shellcode");
    }
  }</pre>
<p>Le shellcode a été copié, il ne reste plus qu&rsquo;à mettre à jour <code>esp</code> et <code>eip</code> en les faisant pointer sur le shellcode. En fait, nous décalons légèrement <code>eip</code> afin d&rsquo;être sûr de tomber au milieu des <code>nops</code>.</p>
<pre>  //Make eip and esp point to the shellcode
  printf("[+] Setting eip and esp...n");
  regs.eip = (int) addr_shellcode+2;
  regs.esp = (int) addr_shellcode;
  res = ptrace(PTRACE_SETREGS, pid, NULL, &amp;regs);
  if(res == -1){
    perror("Setting eip and esp");
  }</pre>
<p>Mission accomplie, plus qu&rsquo;à se détacher pour libérer le processus.</p>
<pre>  //Detach from the process
  printf("[+] Detaching...n");
  res = ptrace(PTRACE_DETACH, pid, NULL, NULL);
  if(res == -1){
    perror("Detaching");
  }</pre>
<p>Pour comprendre en détails les arguments de chaque appel à <code>ptrace()</code>, je vous conseille fortement de lire le manuel.</p>
<h3>Conclusion</h3>
<p>Ca y est, nous venons d&rsquo;arriver au bout de l&rsquo;injection. J&rsquo;espère que vous avez désormais une idée plus claire sur le fonctionnement général de l&rsquo;injection de code sous Linux. Cela m&rsquo;aura pris 3 jours pour arriver à un prototype fonctionnel, mais je ne suis vraiment pas déçu compte tenu du résultat. Si vous avez des remarques, n&rsquo;hésitez pas !</p>
<h3>Références</h3>
<ul>
<li>[1] <a href="http://www.hick.org/code/skape/papers/needle.txt">Linux X86 run-time process manipulation</a>, skape, Uninformed, 2003</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.segmentationfault.fr/projets/injecso-injection-de-so-sous-linux/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
	</channel>
</rss>
