xorl %eax, %eax

OpenSSH ‘sftp-server’ Remote Security Vulnerability

with 2 comments

In the ChangeLog of OpenSSH 7.6 there is only one security fix, and I couldn’t find any associated CVE ID to it. It is basically a design flaw of sftp-server when in read-only mode. Theoretically, read-only should not allow any write operations but Michal Zalewski discovered that you can create zero-length files.

 * sftp-server(8): in read-only mode, sftp-server was incorrectly
   permitting creation of zero-length files. Reported by Michal
   Zalewski.

The vulnerability was located in sftp-server.c source code file and it affected all versions from OpenSSH 5.5 until 7.6 where it was fixed. If the SFTP server starts with the -R flag, it will enable the “readonly” variable as you can see below. This indicates that the clients are not allowed to perform and write operations.

int
sftp_server_main(int argc, char **argv, struct passwd *user_pw)
{
	...
	while (!skipargs && (ch = getopt(argc, argv,
	    "d:f:l:P:p:Q:u:cehR")) != -1) {
		switch (ch) {
	...
		case 'R':
			readonly = 1;
			break;
	...
}

The file opening for SFTP server is performed via process_open() helper function which was opening the files for read-only mode as shown below.

static void
process_open(u_int32_t id)
{
	...
	if (readonly &&
	    ((flags & O_ACCMODE) == O_WRONLY ||
	    (flags & O_ACCMODE) == O_RDWR) != 0)) {
		verbose("Refusing open request in read-only mode");
		status = SSH2_FX_PERMISSION_DENIED;
	} else {
		fd = open(name, flags, mode);
	...
}

As you can see, if “readonly” flag is enabled, it will check if the opening flags “WRITE ONLY” or “READ/WRITE” exist and if this is the case it will error out with “Refusing open request in read-only mode”. Otherwise, it will open the file using open() system call. This looks correct but it doesn’t take into account other argument flags of open() system call such as O_CREAT (create file) or O_TRUNC (truncate file). Those were the flags that M. Zalewski used to create arbitrary files in a read-only SFTP server. To fix this, OpenSSH developers changed the logic of this check to ensure that it will error out if the flag is not O_RDONLY (Read-only) or it includes O_CREAT or O_TRUNC flags. You can see the patch below.

 	if (readonly &&
-	    ((flags & O_ACCMODE) == O_WRONLY ||
-	    (flags & O_ACCMODE) == O_RDWR)) {
+	    ((flags & O_ACCMODE) != O_RDONLY ||
+	    (flags & (O_CREAT|O_TRUNC)) != 0)) {
 		verbose("Refusing open request in read-only mode");

Written by xorl

November 13, 2017 at 23:08

Posted in vulnerabilities

Security BSides Amsterdam 2017

leave a comment »

The first ever Security BSides event in Amsterdam took place in September 2017. The location of the event was the “Zalen Pakhuis de Zwijger B.V.” conference center which is located right next to Amsterdam central station.



There were two simultaneous sessions/tracks. One was secure programming and WebGoat workshops by BSides team together with OWASP. The second was a series of security related presentations. Below is a list of the presentations, and you can watch the recordings in the official YouTube channel of the event here.

  • What if we really assumed breach? – Kevin Jonkers
  • Requiem For An Admin – Walter Legowski
  • Demystifying the Ransomware and IoT Threat – Christopher Elisan
  • To click or not to click, or how to build awareness about behavior online – Jelena Milosevic
  • To pin or not to pin: an introduction into SSL pinning for Android & iOS – Jeroen Willemsen
  • V!4GR4: Cyber-Crime, Enlarged – Ben Herzberg
  • I Thought I Saw a |-|4><0.- – Thomas V. Fischer
  • Bots Combine! : Behind the Modern Botnet – Andrea Scarfo
  • The hidden horrors that 3 years of global red-teaming have revealed to me – Jos van der Peet
  • I Boot when U-Boot – Bernardo Maia Rodrigues & Vincent Ruijter
  • Automating security with PowerShell – Jaap Brasser
  • Behavioral Analysis using DNS, Network Traffic and Logs – Josh Pyorre

Very nice event. Relatively small but it was the first time so it was expected. Congratulations to the organizers for the perfect flow and to the presenters for sharing their research, knowledge, and experience. Hope to be there again next year.

Written by xorl

November 12, 2017 at 11:06

Posted in conferences

OPSEC fail: TanieRC

with one comment

So, a few hours ago I noticed that Sh1ttyKids mentioned the OPSEC fail of a darkweb illegal drug dealer, the TanieRC. So, I decided to make a more detailed post about it in order to help more people discover and report those cyber-crime websites to the authorities. So, let’s see what’s TanieRC…



TanieRC is a Polish illegal drug dealer that started in 20 October 2017. Here is where the OPSEC of this threat actor failed, using Censys.io you can search for the contents of an indexed website. In this case, searching for IPv4 entries that include “taniercil76mgjl3.onion” which is part of the website as you can see in the HTML code of the page, reveals the real IP address of this Tor hidden service. A big fail in the server configuration as the whole purpose of a Tor hidden service is to hide the actual servers that are serving the content.



This is clearly an operational security fail on the cyber-criminal side. Below is a quick list what we learned from this OPSEC failure in this particular case.

IP address        : 193.70.95.90
Hostname          : ip90.ip-193-70-95.eu
Onion address     : taniercil76mgjl3.onion
Web server        : nginx 1.2.1
SSH daemon        : OpenSSH 6.0p1
Operating System  : Debian-4+deb7u2 
SSH fingerpint    : e2890700ba42d5baf545a61afe1427fe24a0472bfafe79d6b8563e3ba6caf95d
Available services: HTTP, SSH, FTP

 
Starting with a WHOIS it is clear that this server is not hosted directly to the French OVH, but instead it is from a small Polish hosting provider called IQ-Group that registered this range in 11 September 2017. The IQ-Group itself was registered in RIPE in 06 July 2017.

inetnum:        193.70.95.80 - 193.70.95.95
netname:        OVH_151685543
country:        PL
descr:          Failover Ips
org:            ORG-IA1520-RIPE
admin-c:        OTC12-RIPE
tech-c:         OTC12-RIPE
status:         ASSIGNED PA
mnt-by:         OVH-MNT
created:        2017-09-11T15:33:27Z
last-modified:  2017-09-11T15:33:27Z
source:         RIPE

organisation:   ORG-IA1520-RIPE
org-name:       Adam Buhl IQgroup
org-type:       OTHER
address:        10 Sudeckiej Dywizji Zmechanizowanej 4
address:        45-828 Opole
address:        PL
e-mail:         abuhl@iq-group.pl
phone:          +48.609651027
abuse-c:        ACRO9280-RIPE
mnt-ref:        OVH-MNT
mnt-by:         OVH-MNT
created:        2017-07-06T08:16:12Z
last-modified:  2017-10-30T14:49:52Z
source:         RIPE

 
Since this is tiny IP range, we can easily scan it to see if there are any other illegal websites hosted there. The result is the following.

193.70.95.80 - not used
193.70.95.81 - not used
193.70.95.82 - not used
193.70.95.83 - not used
193.70.95.84 - not used
193.70.95.85 - Apache2 Ubuntu Default Page, Postfix, & SSH
193.70.95.86 - Apache2 Ubuntu Default Page, Postfix, & SSH
193.70.95.87 - Apache2 Ubuntu Default Page, Postfix, & SSH
193.70.95.88 - Apache2 Ubuntu Default Page, Postfix, & SSH
193.70.95.89 - PHP info page, Postfix, & SSH
193.70.95.90 - TanieRC (drug dealer)
193.70.95.91 - webkillerr.xaa.pl
193.70.95.92 - Apache2 Ubuntu Default Page, Postfix, & SSH
193.70.95.93 - GGspeak.pl
193.70.95.94 - not used
193.70.95.95 - not used

 
This suspicious hosting provider also points to an address (10 Sudeckiej Dywizji Zmechanizowanej 4, 45-828 Opole) which leads to some industrial area of warehouses. Kind of an an unusual place for a small hosting company. Here is a photo from Google Street View for the specified address.



Again, none of those directly relate the hosting provider company with the drug dealer, but it is definitely a relationship that needs some further investigation. In the future I will post more of those quick investigations from failed OPSEC of illegal websites. Hope that you liked it. :)

Written by xorl

November 11, 2017 at 22:54

Posted in opsec

CVE-2017-13090: wget file retrieval integer overflow

leave a comment »

This is similar to CVE-2017-13089 with the only difference being that it leads to a heap based buffer overflow instead of a stack based one. Again, it was reported by Antti Levomäki, Christian Jalio, Joonas Pihlaja of Forcepoint as well as Juhani Eronen of the Finnish National Cyber Security Centre and it is related to the signed integer “remaining_chunk_size”. However, this time it is in the file retrieval code of GNU wget which is located at src/retr.c.

/* Read the contents of file descriptor FD until it the connection
   terminates or a read error occurs.  The data is read in portions of
   up to 16K and written to OUT as it arrives.  If opt.verbose is set,
   the progress is shown.

   TOREAD is the amount of data expected to arrive, normally only used
   by the progress gauge.

   STARTPOS is the position from which the download starts, used by
   the progress gauge.  If QTYREAD is non-NULL, the value it points to
   is incremented by the amount of data read from the network.  If
   QTYWRITTEN is non-NULL, the value it points to is incremented by
   the amount of data written to disk.  The time it took to download
   the data is stored to ELAPSED.

   If OUT2 is non-NULL, the contents is also written to OUT2.
   OUT2 will get an exact copy of the response: if this is a chunked
   response, everything -- including the chunk headers -- is written
   to OUT2.  (OUT will only get the unchunked response.)

   The function exits and returns the amount of data read.  In case of
   error while reading data, -1 is returned.  In case of error while
   writing data to OUT, -2 is returned.  In case of error while writing
   data to OUT2, -3 is returned.  */

int
fd_read_body (const char *downloaded_filename, int fd, FILE *out, wgint toread, wgint startpos,

              wgint *qtyread, wgint *qtywritten, double *elapsed, int flags,
              FILE *out2)

The comment description of this function is more than detailed so without any further discussion, let’s dive into the vulnerability which is part of fd_read_body() function.

int
fd_read_body (const char *downloaded_filename, int fd, FILE *out, wgint toread, wgint startpos,

              wgint *qtyread, wgint *qtywritten, double *elapsed, int flags,
              FILE *out2)
{
	...
  int dlbufsize = max (BUFSIZ, 8 * 1024);
  char *dlbuf = xmalloc (dlbufsize);
	...
  wgint remaining_chunk_size = 0;
	...
      if (chunked)
        {
          if (remaining_chunk_size == 0)
            {
              char *line = fd_read_line (fd);
	...
              remaining_chunk_size = strtol (line, &endl, 16);
	...
          rdsize = MIN (remaining_chunk_size, dlbufsize);
	...
      ret = fd_read (fd, dlbuf, rdsize, tmout);
	...
}

Just like in CVE-2017-13089, “remaining_chunk_size” is initialized from the user controlled value of the file in hexadecimal form, which could lead to a negative value. Then this is compared using MIN() macro and used to initialize signed integer “rdsize” which is then used as a counter for fd_read() which in turn, copies data from the file to the heap-based “dlbuf” buffer. If “rdsize” has been exploited to contain a negative value (integer overflow), it will result in a heap-based buffer overflow of “dlbuf” during the fd_read() call. The patch was to add a bounds check to ensure that the “remaining_chunk_size” is not overflowed to a negative value after the strtol() invocation.

               remaining_chunk_size = strtol (line, &endl, 16);
               xfree (line);
 
+              if (remaining_chunk_size < 0)
+                {
+                  ret = -1;
+                  break;
+                }
+
               if (remaining_chunk_size == 0)

Written by xorl

November 11, 2017 at 20:43

Posted in vulnerabilities

CVE-2017-13089: wget HTTP integer overflow

leave a comment »

That’s an interesting vulnerability in GNU wget. According to the wget project, this was reported by Antti Levomäki, Christian Jalio, Joonas Pihlaja of Forcepoint as well as Juhani Eronen of the Finnish National Cyber Security Centre. The vulnerability is in src/http.c source code file and more precisely in skip_short_body() function.

/* Read the body of the request, but don't store it anywhere and don't
   display a progress gauge.  This is useful for reading the bodies of
   administrative responses to which we will soon issue another
   request.  The response is not useful to the user, but reading it
   allows us to continue using the same connection to the server.

   If reading fails, false is returned, true otherwise.  In debug
   mode, the body is displayed for debugging purposes.  */

static bool
skip_short_body (int fd, wgint contlen, bool chunked)
{
  enum {
    SKIP_SIZE = 512,                /* size of the download buffer */
    SKIP_THRESHOLD = 4096        /* the largest size we read */
  };
  wgint remaining_chunk_size = 0;
	...
  return true;
}

The description in the comment is pretty clear but what we care about here is the “remaining_chunk_size” variable which has data type of “wgint”. This is a data type defined in src/wget.h header file based on the architecture and operating system.

/* Pick an integer type large enough for file sizes, content lengths,
   and such.  Because today's files can be very large, it should be a
   signed integer at least 64 bits wide.  This can't be typedeffed to
   off_t because: a) off_t is always 32-bit on Windows, and b) we
   don't necessarily want to tie having a 64-bit type for internal
   calculations to having LFS support.  */

#ifdef WINDOWS
  /* nothing to do, see mswindows.h */
#elif SIZEOF_LONG >= 8
  /* long is large enough, so use it. */
  typedef long wgint;
# define SIZEOF_WGINT SIZEOF_LONG
#elif SIZEOF_LONG_LONG >= 8
  /* long long is large enough and available, use that */
  typedef long long wgint;
# define SIZEOF_WGINT SIZEOF_LONG_LONG
#elif HAVE_INT64_T
  typedef int64_t wgint;
# define SIZEOF_WGINT 8
#elif SIZEOF_OFF_T >= 8
  /* In case off_t is typedeffed to a large non-standard type that our
     tests don't find. */
  typedef off_t wgint;
# define SIZEOF_WGINT SIZEOF_OFF_T
#else
  /* Fall back to using long, which is always available and in most
     cases large enough. */
  typedef long wgint;
# define SIZEOF_WGINT SIZEOF_LONG
#endif

What is worth noting is all of the type definitions are using signed data types. This means that “wgint” variables can get both positive and negative values. Now that this is clear, let’s move back to http.c and skip_short_body() function.

static bool
skip_short_body (int fd, wgint contlen, bool chunked)
{
	...
    SKIP_SIZE = 512,                /* size of the download buffer */
	...
  wgint remaining_chunk_size = 0;
  char dlbuf[SKIP_SIZE + 1];
	...
  while (contlen > 0 || chunked)
    {
      int ret;
      if (chunked)
        {
          if (remaining_chunk_size == 0)
            {
              char *line = fd_read_line (fd);
              char *endl;
              if (line == NULL)
                break;

              remaining_chunk_size = strtol (line, &endl, 16);
              xfree (line);
	...
          contlen = MIN (remaining_chunk_size, SKIP_SIZE);
	...
      ret = fd_read (fd, dlbuf, MIN (contlen, SKIP_SIZE), -1);
	...
}

So, when wget processes chunked responses it will enter this “while” loop (content length greater than zero or the response is chunked). When the chunk size gets to 0, it will read the next line using fd_read_line() and then attempt to retrieve the remaining chunk size using strtol() in hexadecimal. This value is 100% controlled by the response header and it could be anything, including so large that it will wrap around this signed integer into a negative value. Then MIN() macro will be used to compare that value with SKIP_SIZE (which is 512) and use this to initialize “contlen” signed integer. If “remaining_chunk_size” had a negative value it means that this will now be stored in “contlen” which is then used in fd_read() leading to a stack based buffer overflow as the attacker completely controls the size argument that is used to copy data from “fd” (the HTTP page) to “dlbuf” (stack based buffer with size of 513 bytes). The fix was relatively simple as you can see below.

               remaining_chunk_size = strtol (line, &endl, 16);
               xfree (line);
 
+              if (remaining_chunk_size < 0)
+                return false;
+
               if (remaining_chunk_size == 0)

The fix was a simple bound check after the strtol() call to ensure that the value of “remaining_chunk_size” was not set to a negative value before continuing with the processing.

Written by xorl

November 11, 2017 at 16:32

Posted in vulnerabilities

Cyber Threat Intelligence and the Association Matrix

leave a comment »

Nowadays most intelligence analysts are spoiled with 3rd generation analysis tools such as Palantir, IBM i2 Analyst’s Notebook, etc. However, it is useful to occasionally learn about the earlier methods of intelligence analysis which can be valuable under certain conditions. One of those 2nd generation intelligence analysis methods is the association matrix which looks like what you see here.



This matrix is used to associate threat actors with a specific location, organization/group, property, incident, weapon, and/or modus operandi. The aim is to generate actionable information that will assist in focusing the intelligence collection to a smaller set of targets. It is important though to remember what counter-intelligence field manuals always state about this analysis method:

An important point to remember about using the association matrix is that it will, without modification, show only the existence of relationships; not the nature, degree, or duration of those relationships.

The association matrix typically lists the threat actors on the right side of the pyramid, and inside the association can be marked with a solid circle (denotes a confirmed relationship), an open circle (denotes suspected linkage), or the plus symbol (denotes a key individual).



It is also worth noting that military intelligence occasionally includes footnotes which are represented as a subscript number on the bottom right of the marking as shown below. The below association matrix describes a confirmed relationship of CARTER and JONES, who both attended CCNY in 1988-1991.



In CTI (Cyber Threat Intelligence) association matrix is useful even today. If you have a large amount of malicious activity and you want to prioritize your intelligence collection to the threat actors that are more dangerous to your organization, you can do a simple association matrix of them and start with the ones with the largest amount of relationships (and trust me, you will be impressed when you’ll find that you are dealing with 10 groups instead of one thousand independent threat actors).

So, that was it. Please let me know if you had any success on your CTI using the association matrix.

Written by xorl

November 11, 2017 at 13:31

Wireshark dynamic button to filter source IP

leave a comment »

Yesterday I learned a super useful trick for Wireshark. The idea is to have a button in Wireshark‘s GUI that you can click when you have selected a frame for a source IP you are interested in, and it will dynamically create a filter to show you only the frames that are related to this IP address. Let’s start. (Below I used the HTTP.cap file from packetlife.net)

Step 1: Magic of variable searching
We all know that in the filter bar of Wireshark we can write a simple filter based on the source IP address. For example, to find all the communication of source IP address 192.169.1.140 the filter would look like this.

ip.src == 192.168.1.140

You can see how this looks like in the GUI in the following screenshot.



That’s something that everyone who ever used with Wireshark knows really well. The magic part is that you can also do dynamic matching. For example, the following filter says “filter the source IP address that matches the source IP address of the frame I have currently selected

ip.src == ${ip.src}

And you can see it in action here.



This is how you can do dynamic filtering in Wireshark. Let’s move to the next step, operationalizing this.

Step 2: Transform a filter to a button
Wireshark allows easy creation of custom buttons. To create and save this filter is super easy. You can see how it’s done below.







From that point on, the moment you find a frame that you are interested in searching on the source IP, just click on that custom button and you’ll get a view of the packets from this source IP address only.

Step 3: ???
Well, that’s up to your imagination and your needs. You can do it for almost any part of a frame or packet. You can include regular expressions, limits, etc… Efficient and it really simplifies packet analysis. :)

Written by xorl

November 11, 2017 at 01:00

Posted in tips