Wednesday, September 1, 2021

Getting uniqe docker container name from within container

I had a use case in which I needed to obtain a unique identifier of a container from within the container. The problem is that container is started with docker-compose using scale option so that a number of indentical containers are started. Googling around gave me some options like examining /proc/self/cgroups, but in my case, this file didn't contain anything useful. Another solution was to pass environment variable from the outside which also looked like a mess. In the end, I came up with not so elegant solution, but the one that works. I use Python, but the concept could be used with other programming languages as well.

First, environment variable contains image name, e.g. crawler. So, you can use the following Python expression to obtain this name:

import os
hostname = os.environ['HOSTNAME']

Variable hostname will contain crawler in our example. Next, resolve this name to IP address:

import socket
ip = socket.gethostbyname(hostname)

This will give you IP address of the container, e.g. 172.25.0.12. Now, you should do a reverse lookup. BUT, you can not use gethostbyaddr since it will return to you the same hostname as the one you obtained from HOSTNAME environment variable. The reason is that gethostbyname and gethostbyaddr use /etc/hosts file first. Instead, you have to use DNS. Unfortunately, this is where external library is needed. You can install and use dnspython, and then do a reverse lookup:

from dns import resolver,reversename
addr=reversename.from_address(ip)
str(resolver.resolve(addr,"PTR")[0]).split('.')[0]

The reason for the last mess is that resolver.resolve returns tupple with FQDN in the zero-th element, and then FQDN has to be splitted on dots to take the hostname only.

Thursday, August 22, 2019

List directory sorted by length of names in it

So, for whatever reason, while running ls command, I wanted my directory to be sorted by the length of the names in it, not by some other sorting method ls uses. After a bit of trial and error experimenting, I ended up with the following pipeline to do that:
for i in *; do echo `echo "$i" | wc -c` "$i"; done | sort -n | cut -f2- -d" " | xargs -d \\n ls -Uld
Let's break this command into peaces and describe what it does.

The first compound command starting with for and ending with the first pipe character has a task to output length of a name following by a space and then by name itself. You can try to run it within some directory and what you'll get will look similar to this:
1 a
4 name
7 testing
2 ab
What we've got is something to sort on (number a.k.a. length) and we keep name as well since we need it for later.

The next command in pipeline will sort this output so that the shortest name is first, following the longer ones and finally ending up with the longest name, i.e. we'll get
1 a
2 ab
4 name
7 testing
Since we have now sorted names we don't need length any more and thus we get rid of it using cut command as the next command in the pipeline. The output after cut command will look like this:
a
ab
name
testing
Now, if there are no spaces in the names, then it's easy, just hand over this list to the ls command. The command would then look like this:
ls -Uld `for i in *; do echo `echo "$i" | wc -c` "$i"; done | sort -n | cut -f2- -d" "`
Note backticks before for and at the end of the command line! The options U, l and d cause ls not to sort anything (U), to provide long output (l) and not to list content of directories (d).

But, in case there are spaces in names, this will fail horribly, as many other things do when they encounter spaces in names. So, the trick used in this case was to employ xargs command that collects standard input and runs command with certain number of arguments collected from stdin. The xarg command is
xargs -d \\n ls -Uld
In this command with option d we are telling xargs that delimiter between arguments is new line, and not space which is default setting. The rest of the line xargs takes as-is and just adds arguments and runs a command.

And that's it!

By the way, I also unsuccessfully tried to collect arguments into array by reading names with while loop (and read command). The problem is that any variable being set within while command is lost after while finishes and I didn't managed to pass this out of the while loop.

Wednesday, July 4, 2018

Cracking raw MD5 hashes with John the Ripper

I just spent at least 15 minutes trying to figure out why every single post on the Internet tells me to place MD5 hash in a file and call John like this
john --format=raw-md5 --wordlist=/usr/share/dict/words md5.txt
and yet, it constantly gives me an error message:
No password hashes loaded (see FAQ)
The content of md5.txt was:
20E11C279CE49BCC51EDC8041B8FAAAA
I even tried prepending dummy user before this hash, like this:
dummyuser: 20E11C279CE49BCC51EDC8041B8FAAAA
but without any luck.

And of course I have extended version of John the Ripper that support raw-md5 format.

It turned out that John doesn't support capital letters in hash value! They have to be written in small letters like this:
20e11c279ce49bcc51edc8041b8fbbb6
after that change, everything worked like a charm. What a stupid error!?

About Me

scientist, consultant, security specialist, networking guy, system administrator, philosopher ;)

Blog Archive