Showing posts with label shell. Show all posts
Showing posts with label shell. Show all posts

Friday, May 18, 2018

Vimifier!


If you've seen my blog, you know I love Vim. And if you've worked with me, you know I hate when I have to use editors like Microsoft Word because I have to take my fingers off the home row so much to select text, frequently change its format, and generally get around and edit what I'm working on. I worked on a 72-page report last week where I lamented this extensively. Over the week, I started to think: what stops me from turning the keystrokes I want to type into the keystrokes I am typing?

For instance, when I want to move the cursor between words, I use Ctrl+Left and Ctrl+Right. And when I want to select several words, I hold down the shift key. I started to wonder how hard it might be to create a keyboard hook that would translate Vim-style shortcuts (like b, w, v, ...) into their Windows hotkey equivalents (Ctrl+Left, Ctrl+Right, Shift, ...).

Well, I tried it out, and yeah it's a bit of work, but it's worth it! I don't have screenshots or GIFs because it's hard to make it evident what keystrokes I'm using, but if you're a tinkerer then take a look and try it out. I think you'll be amused!

Get the source code under my GitHub profile at https://github.com/strictlymike/vimifier.

If you need a bare bones compiler to get this built, the quickest shortcut I know of is to grab the Microsoft Visual C++ Compiler for Python 2.7.

Sunday, February 28, 2016

Snooping on Myself for a Change

Premise

When I started red teaming, I would often want to know the answers to impossible questions while writing my post-assessment report:
  • What was that command I used that I didn't think would be important to making my point, but now I realize it is?
  • The output indicated a Windows error message - which error was it?
  • Which IP address was leased to me when I did that?
Naturally a red teamer should always be taking copious screenshots, recording IP addresses frequently, and incrementally reporting in tandem with the engagement. But knowing what will be significant later is sometimes a challenge. It would be nice to have a backup.

In this post, I talk about researching and constructing a tool for logging 32-bit cmd.exe commands and output local to one's Windows attack VM. Then I discuss limitations and post source code. I've wanted to do this for a while, but I recently had a project that gave me an excuse to use Detours, so while I was at it, I decided to quickly knock out this project.

Tools

Microsoft Research produced a very useful tool for both investigating this problem and developing a solution, called Microsoft Detours. Detours is a library for hooking Win32 APIs, which allows one to instrument and extend binary applications. The non-commercial version can be downloaded for free, but only covers 32-bit architectures. This will suffice for our proof of concept. These techniques are older than 1999, so I leave it as an exercise for the student to extend this to 64-bit.

One of the Detours samples, named traceapi, hooks 1,401 Windows API functions, and can provide detailed insight into how an application works. Meanwhile, another Detours sample, named simple, shows an example of hooking and extending the Windows SleepEx API. This is all we need to get started.

Investigation

To use the traceapi sample, you must copy the Detours root to a writable directory, open a 32-bit Windows SDK Prompt, and invoke nmake from the samples directory. The bin.x86 Detours sub-directory will contain many files, including the following tools necessary to this exercise:
  • traceapi.dll (or trcapi32.dll - I seem to recall getting different results depending upon how I built this)
  • withdll.exe - for loading an application with a DLL in its address space
  • syelogd.exe - for logging trace output from Detours tools
When using traceapi, I expected to find patterns including CreateFile(CONIN$) / ReadFile, or some such. Then I anticipated hooking functions to record which handles corresponded to CONIN$, CONERR$, and CONOUT$ so that I could know which ReadFileW and WriteFileW activity corresponded to console input and output.

To begin the investigation, I launched syelogd.exe to log to a file, as follows:

C:\Users\someone\Detours\bin.x86> syelogd.exe trace_cmd.log

I then launched the 32-bit cmd.exe with traceapi.dll in its address space to begin tracing:

C:\Users\someone\Detours\bin.x86> withdll.exe /d:traceapi.dll C:\Windows\SysWOW64\cmd.exe

At this point, I typed a few commands like DIR and EXIT, and then terminated syelogd.exe.

Ah, beautiful trace output

What I found was happily contrary to my expectations...

Found the "Easy" button

The Windows command interpreter uses the ReadConsole and WriteConsole APIs for reading to and writing from the console. All the easier to hook, with no state tracking required.

Development and Features

The Detours sample named simple contains all you need to get started. Copy that folder, name it something else, update the Makefile, and get cooking. One bump I ran into and hacked up a fix for was that the 32-bit rc.exe crashed when executing it within my 32-bit Windows SDK Prompt. This is why my own Makefile (not uploaded) directly references the 64-bit rc.exe.

Logging

To customize the sample code to do my bidding, I followed the simple example's hooking pattern to first hook ReadConsoleW and WriteConsoleW. My initial logging hooks simply returned the value of the real functions just for testing purposes. I then tried printf("WriteConsole: %S", lpBuffer) to test whether I could output the data, and finally opened a file within the DllMain function.

Here is an example of the logging for a call to net.exe:
Logs for days
Why is there a separate log for each process? Because my DLL creates a new, unique log every time it is loaded. See the Limitations section below for discussion.

Why does net.exe create two logs? Because net.exe calls out to net1.exe to do its work.

IP Address Logging

I expected to have to use some sort of COM API, but instead there's this convenient GetAdaptersInfo API. Easy-peasy :)

Status Command

I wanted a way of knowing for sure that logging was enabled, without typing EXIT and having my parent prompt close on me. So, I implemented a secret command, REM status. Because my command begins with the REM command, it will be ignored by the command interpreter but intercepted by my hook on its way to the application.

BOOL WINAPI
LogReadConsoleW(
  HANDLE  hConsoleInput,
  LPVOID  lpBuffer,
  DWORD   nNumberOfCharsToRead,
  LPDWORD lpNumberOfCharsRead,
  PCONSOLE_READCONSOLE_CONTROL pInputControl
)
{
    BOOL ret = pReadConsoleW(
        hConsoleInput,
        lpBuffer,
        nNumberOfCharsToRead,
        lpNumberOfCharsRead,
        pInputControl
       );

    /* TODO: Replace this crap code with more accurate parsing */
    if (!wcsncmp((const wchar_t *)lpBuffer, CMD_QUERY_STATUS,
                wcslen(CMD_QUERY_STATUS)))
    {
        printf("Logging to %s\n", cmdlog_fname_expanded);
        LogInfoStampToFile(stdout);
    }

    LogToFile(cmdlog, "%S", lpBuffer);
    State = clsLabel;

    return ret;
}

The result is satisfactory. I type REM status, and if I'm hooked, I see a nice little confirmation that logging is enabled, including the log file name and some IP address information.

Yes, Neo, you are in the Matrix.

Limitations

Otherwise known as "problems I don't plan to solve until I get a copy of Detours Enterprise and some more time." The last 10% always takes 90% of the time, amirite?

Single-File Logging

This will probably entail using IPC, and some IPC mechanisms (like named pipes) cannot be initialized in DllMain because they could cause a deadlock by precipitating an attempt to acquire the loader lock (check out Microsoft's article on DLL best practices). This means writing "lazy initialization" code. I leave this as an exercise for the student.

Another scheme is for each child to share a log file with the parent process whose name is based on the PID of the top-most parent of the current process that has our DLL loaded in its address space. The APIs used to do this might entail a LoadLibrary or some APIs that violate DLL best practices, so again... Exercise left for the student.

Alternately, I could just open and close a single logfile with a single name, but then if I open several logged command prompts, one may fail to get access to the log as another is writing to it (say, if I'm running a command that outputs continuously while running another command in the other prompt). So, I didn't do that.

Cross-Architecture Process Creation

Because Detours Express is only for 32-bit, we have no 64-bit DLL. So here's what happens when you try to load a 64-bit process...

Nope.
Hooking 64-bit, while fun, is not something I have time for right now (I'm a father; give me a break). But my employer has a license for 64-bit, so perhaps I will extend this later. How? I anticipate that I will use the ImageHlp APIs or something to figure out whether the CreateProcess call is for a 32- or 64-bit process, and then load the appropriate DLL. Yay!

^M&^M's

If you open the output log files in something like gvim, you will see stray ^M's (character 0x0d) all over the place. Yuck. But a quick swipe of the %s/^M//g in gvim eliminates these, so I just can't bring myself to care.

Source Code

As is frequently the case with my spare-time experimentation, this code is proof of concept only. If it doesn't compile because I didn't close a pair of parentheses, rest assured that it's because I had to drop everything and rush over to my young daughter to prevent her from acquainting herself with an electric socket. Forgive me. But hopefully the thought process published here and the examples available in the code will help you think of new ways to solve problems.

The code is here: https://github.com/strictlymike/tools/tree/master/cmdlog

Monday, February 2, 2015

Clip Snippet


Quickie: you run a command, then want its output in your Word document (because, for some reason, customers won't accept .TXT files as deliverables).  Try pressing the up arrow to queue the previous command to be repeated, and then piping it to CLIP.EXE:

ipconfig /all | clip

Check this little guy out (from CLIP /?):

CLIP

Description:
    Redirects output of command line tools to the Windows clipboard.
    This text output can then be pasted into other programs.

Parameter List:
    /?                  Displays this help message.

Examples:
    DIR | CLIP          Places a copy of the current directory
                        listing into the Windows clipboard.

    CLIP < README.TXT   Places a copy of the text from readme.txt
                        on to the Windows clipboard.

Yeahhhh.  It'll copy its input into the clipboard.  Not bad :-)

Tuesday, January 20, 2015

Windows man pages

If you're a UNIX or Linux person, you know Windows lacks man pages.  So man up and make some.

Create a directory and add it to your path.  Call it man, help, or whatever.

Every time you run into a command whose usage and arguments you need to know, run it with the /? switch and redirect its output into a file in that help directory.

FOR /? > %USERPROFILE%\help\for.txt

Now you've got a file in your path that says this:

Runs a specified command for each file in a set of files.

FOR %variable IN (set) DO command [command-parameters]

  %variable  Specifies a single letter replaceable parameter.
  (set)      Specifies a set of one or more files.  Wildcards may be used.
  command    Specifies the command to carry out for each file.
  command-parameters
             Specifies parameters or switches for the specified command.

To use the FOR command in a batch program, specify %%variable instead
...

Then, the next time you need help on the for command, hit Win+R, type for.txt, and press Enter.  The saved help will pop up immediately in Notepad, because you added the help directory (or whatever you called it) to your path.  You can also use it to stash past examples if you're running or scripting particularly complex commands.

Presto.  Man pages.  Now quit yer whining.

Monday, December 29, 2014

How to Stop Bashing and Take CMD

A colleague of mine is a Linux hacker who took a job in Seattle and has been thrust into Windows.  On his team, PowerShell is not always available, so he's left saying "look dude, I know bash; what the heck do I do with this??"  If you're in a similar situation, this is a primer for you.

Below are a few bash-isms and Unix-isms, and their cmd.exe analogues, as well as some things that are purely from CMD.  To try them, open up cmd.exe (Start > Run: cmd.exe, or Windows+R: cmd.exe) and go to town.

One-Liners

I'll start with some one-liners.  The $ prompt indicates commands that can be used in bash on GNU/Linux and similar operating systems, and the > prompt represents the cmd.exe equivalent.  Omit the prompts ($ and >) when trying these commands.

Run something else
$ bash -c something else
> cmd /c something else
> cmd /k something else

In the latter command, cmd will stay resident and permit further commands.

Display program return value:
$ echo $?
> echo %ERRORLEVEL%

Some programs, when they are run, return a numeric status code.  Generally, 0 indicates success, and 1 or greater indicates an error.  Windows executables that display graphical windows (calc.exe and winword.exe are examples) return 0 immediately and unconditionally, and run "asynchronously" -- meaning, the command prompt receives the return value immediately and allows the user to type more commands.

Compare program return value:
$ if [ $? -eq 0 ]; then echo Success; fi;
> if %errorlevel% == 0 echo Success

Find program in path:
$ which which
> where where


Find file:
$ find / -type f -name whatever\*.txt
> dir /s \whatever*.txt
> dir /a/b/s \whatever*.txt

The latter command will show all files, even those having the hidden attribute (/a) and will provide bare output without any file sizes or other details (/b).

Find string in files:
$ grep -Ri needle *
> findstr /S /I needle *

Find string in program output:
$ ifconfig | grep 192
> ipconfig | findstr 192

Start service (e.g. mysql):
$ service mysql start
> sc start mysql
> net start mysql

The latter command (net.exe) can do many things including viewing and modifying local groups, authenticating to network shares and mapping them to drive letters, etc.  The other command (sc.exe) is strictly for starting and stopping services, viewing their configuration, and other tasks.

Restart web server:
$ apachectl -k restart > /dev/null 2>&1
> iisreset > nul 2>&1


Terminate by pid:
$ kill -s 9 916
> taskkill /f /PID 916


Terminate by name:
$ killall -s 9 kcalc
> taskkill /f /IM calc.exe


Shut down:
$ shutdown -h now
> shutdown /s /t 0


Reboot: 
$ shutdown -r now
$ reboot
> shutdown /r /t 0


Add user to group: 
$ useradd -G root mike
> net localgroup administrators /add mike


Set environment variable:
$ variable=hello
> set variable=hello


Display environment variable: 
$ echo $variable
> echo %variable%


Prompt for environment variable:
$ read -p "Type something: " variable
$ echo $variable
> set /p variable=Type something:

> echo %variable%

Pre-set variables such as username:
$ echo $USER
> echo %username%


Dump environment: 
$ setenv
> set


The SET command also accepts partial variable names, and will list all the variables and values whose names match that string.

Compare files:
$ cmp file1 file2
> fc file1 file2

You can check the errorlevel (the numeric error or success code returned by the program) to determine whether the files are the same.  Identical files result in a 0 errorlevel, and differing files result in a return value of 1 or greater.

Display file contents:
$ cat file
> type file

> more file

The latter command, more, can be used to display the contents of those notorious alternate data streams, and also serves as a pager (see next).

Display file contents with pager:
$ less file
$ cat file | less
> more file
> type file | more


Loops:
$ for ((n=2; n<=8; n+=2)); do echo $n; done
> for /l %n in (2, 2, 8) do echo %n


Operate on a set of arbitrary words: 
> for word in hello there; do echo $word; done
$ for %w in (hello there) do ( echo %w )


Echo the names of all text files in the current dir:
 > for file in *.txt; do echo $file; done
$ for %f in (*.txt) do echo %f


Echo the names of all text files recursively: 
$ for file in $(find . -name \*.txt); do echo $file; done
> for /f "usebackq" %f in (`dir /a/b/s *.txt`) do echo %f
> for /r %f in (*.txt) do echo %f


Parse IP addresses out of IP configuration:
 $ echo IP: $(ifconfig | grep 'inet addr' | awk -F: '{print $2}' | awk '{print $1}')
>for /f "usebackq delims=: tokens=1,2" %a in (`ipconfig ^| findstr /i IPv4`) do echo IP: %b

Scripts

Read file, find pattern, copy to another location

cprintf.sh:
#!/bin/bash

dstdir=~/cfiles;
rm -rf $dstdir;
mkdir $dstdir;

for file in $(find . -type f -name \*.c); do
    grep -i printf $file > /dev/null 2>&1;
    if [ $? -eq 0 ]; then
        cp $file $dstdir;
    fi;
done;


cprintf.cmd:
@echo off

set dstdir=%userprofile%\cfiles
if exist "%dstdir%" rmdir /s /q "%dstdir%"
mkdir "%dstdir%"

for /r %%f in (*.c) do (
    findstr /i printf %%f > nul 2>&1
    if not errorlevel 1 copy %%f "%dstdir%" > nul 2>&1
)


Because of the idiosynchrasies of the Windows command interpreter and native utilities, writing robust scripts for CMD is akin to any of the following activities:
  • Leveling and hanging a picture in an earthquake
  • Making a bed with a rabid dog in it
  • Asking a room full of four-year-olds to each draw a triangle
  • Wrestling with a snake, a crab, and an orangutan at the same time
  • Balancing a system of simultaneous equations by inspection while inebriated
Here are the idiosynchrasies that are relevant to the above script:

Double percent signs (e.g. %%f) are used to denote loop variables in .cmd and .bat files instead of single percent signs (e.g. %f) as on the command line.  Variable names must be a single character in length (e.g. %a on the command line, and %%a in a script file).

Also, evaluation of errorlevels can be done both by comparison with the %ERRORLEVEL% environment variable and using the IF [NOT] ERRORLEVEL construct.  The help for the if command (accessible by typing IF /?) states:

  ERRORLEVEL number Specifies a true condition if the last program run
                    returned an exit code equal to or greater than the number
                    specified.
And:

  NOT               Specifies that Windows should carry out
                    the command only if the condition is false.

Just so you've got that straight: don't ask the command interpreter this:

IF ERRORLEVEL 0 ECHO Oh yes, everything is fine <-- NO, IT IS NOT

There are some more turds in the punch bowl...

If you mean to set variables in a for loop and reflect on those values later in the script, you must first invoke SETLOCAL ENABLEDELAYEDEXPANSION.  To obtain the most up-to-date value of each variable, you must then use exclamation points, not percent signs, to access the data.  For example: !frick!.

If you use a pipe within a backtick expression in a FOR /F "usebackq" statement, escape the pipe with the caret symbol.  For example, `dir /a/b/s *.txt ^| findstr x`.

Windows scripts access arguments as %1, %2, etc.  Tilde modifiers such as %~n0 (equivalent to basename $1) are used to parse filenames, and can be found in the help for the FOR command. 

Environment variables inherently support substring selection and pattern replacement:

C:\Users\mykill>echo %username:kill=ke%
myke

C:\Users\mykill>echo %username:~0,3%
myk


I will probably update this article to include more info.  Suggestions are welcome.

For more loopy help:
for /?

The help from a few other commands can also be informative:
if /?
setlocal /?