No more apt-get prompts
Sometimes you might be installing a package and don’t want it to prompt at all. Apt will prompt you a lot sometimes if you just do an apt-get install packageName. For example
- If you want to install, if there are multiple packages
- Accept package from a signed repo that you don’t have the key for
- If you want to keep the old config
So you can run the following
apt-get -q -y -o DPkg::Options::=--force-confold --force-yes install packageName
grep only stderr from a command
So sometimes you have a command where you want to only grep stderr. For example I use Cronic to manage all my cronjobs. It’s really nice since it sends a nicely formatted email back to you if a command returns anything in stderr. Crontab alone will email me if anything in stdout/stderr is printed out from a command.
There is a problem with cronic though. There’s an app called s3cmd which uploads files to s3 and on large files this output can happen
WARNING: Retrying failed request: /postgresql/2013-05-05_hour-18.sql.bz2?partNumber=1&uploadId=m0gX4xcOU7IDla2B2p55xJXDfih_mm7rDx5bJvucUAmQYC10mwoHXVDjyoat_uzNJBYpedrWu7neakUpH3zGw-- ([Errno 110] Connection timed out)
WARNING: Waiting 3 sec...
This generally happens if the fule is very large. s3cmd will restart the transfer of the part and it will be uploaded just fine. So the main issue is s3cmd has no way to ignore warnings, at least as of 1.5.0-alpha2. If it does, I am overlooking it.
So in order to solve this I have decided I want to grep out the WARNING lines from stderr. Now the easy way to do this is re-direct stderr to stdout and pipe it to grep. Well this sucks cause you will lose valid error output. So the answer is something like this
cmd 2> >(grep -v "WARNING" >&2)
That will then allow you to grep just from stderr and the -v flag will set grep to ignore WARNING lines.
Remove internal hosts in postfix
A proper way to setup your network is to have a postfix relay server sitting somewhere on your network that every other server has access to via port 25. Now your relay server(s) are the only ones that should have outside access to port 25. All other servers should be firewalled off!
So for example say your email chain looks like this for a new signup
web1.domain.com -> mailserver.domain.com -> internet -> user's mailbox
If the user views the email source they will see that the email started at web1.domain.com and it will include your internal IP address. So you are exposing internal IP addresses which isn’t very good at all.
So we can fix this in postfix very easily on the mailserver.domain.com config. For example say your internal network is
10.114.0.0/16
So lets remove them everything in that subnet along with 127.0.0.1. So edit the following file
/etc/postfix/main.cf
Then add the following line
header_checks = regexp:/etc/postfix/header_checks
Now create a new file
/etc/postfix/header_checks
Then add the following in place
/^Received:.*\[127\.0\.0\.1/ IGNORE
/^Received:.*\[10\.114\..*/ IGNORE
Then restart postfix and you are good to go.
How many bits per point in a whisper file in graphite
This is an easy one. You do an ls over a whisper file and get something like
1.1M -rwxr-xr-x 1 root root 1.1M Aug 9 11:06 Active.wsp
Now you are planning to save more metrics in your graphite server or want more points in your retention so you want to plan how much space you’ll need given an estimated guess of your metric count out 6 months from now. So you can run the following over that whisper file to get info on it.
$ whisper-info.py Active.wsp
maxRetention: 31536000
xFilesFactor: 0.5
aggregationMethod: average
fileSize: 1062772Archive 0
retention: 604800
secondsPerPoint: 60
points: 10080
size: 120960
offset: 52
So you see for Archive 0 we have a certain size and number of points. So from here it’s easy math
120960 / 10080 = 12
So for each whisper data point you save it will allocate 12 bits on your filesystem. So you can plan our growth since carbon pre-allocates the space needed for whisper files so your disk isn’t doing any random seeks while pulling up data for your graphs.
Google Authenticator with OpenVPN for 2 factor auth
This post will describe how to get it working with Ubuntu 12.04. It should work with other versions along with other Linux distros. The only difference is the package names might change.
Install the packages
Run the following command
apt-get -y install openvpn libpam-google-authenticator
Setup OpenVPN
Place the cert key helps
mkdir /etc/openvpn/easy-rsa/
cp -R /usr/share/doc/openvpn/examples/easy-rsa/2.0/* /etc/openvpn/easy-rsa/
Then you need to edit the following file
/etc/openvpn/easy-rsa/vars
Scroll all the way down and find the following section and change it to your needs
export KEY_COUNTRY=US
export KEY_PROVINCE=NY
export KEY_CITY=NewYork
export KEY_ORG=”Company VPN”
export KEY_EMAIL=”sysops@company.com”
Set the permissions
cd /etc/openvpn/easy-rsa/
sudo chown -R root:admin .
sudo chmod g+w .
Source the vars file to pull in needed environment variables
source ./vars
Run the scripts to build your keys
./clean-all
./build-dh
./pkitool –initca
./pkitool –server server
cd keys
openvpn –genkey –secret ta.key
sudo cp server.crt server.key ca.crt dh1024.pem ta.key ../../
Create the following file
/etc/openvpn/up.sh
With the contents of
#!/bin/sh
BR=$1
DEV=$2
MTU=$3/sbin/ip link set “$DEV” up promisc on mtu “$MTU”
/sbin/brctl addif $BR $DEV
Then create another file called
/etc/openvpn/down.sh
With the contents of
#!/bin/sh
BR=$1
DEV=$2/sbin/brctl delif $BR $DEV
/sbin/ip link set “$DEV” down
Now set permissions on this files
chmod +x /etc/openvpn/up.sh /etc/openvpn/down.sh
Then you want to add the following to /etc/sysctl.conf
net.ipv4.ip_forward = 1
That will set it on reboot but you want to set it now run the following
echo 1 > /proc/sys/net/ipv4/ip_forward
Now setup pam to work for openvpn. Create the following file
/etc/pam.d/openvpn
Then put the following in
auth requisite pam_google_authenticator.so forward_pass
auth required pam_unix.so use_first_pass
Now you need to edit your openvpn config. I called mine server.conf in /etc/openvpn and you want to add the following
plugin /usr/lib/openvpn/openvpn-auth-pam.so openvpn
Now once openvpn is started you can run the following as the user you are setting up VPN for. They will need a shell account and they can do this themselves if needed. So run the following command
google-authenticator
Then choose the following options in this order.
Do you want authentication tokens to be time-based (y/n) y
Do you want me to update your “/home/bla/.google_authenticator” file (y/n) yDo you want to disallow multiple uses of the same authentication
token? This restricts you to one login about every 30s, but it increases
your chances to notice or even prevent man-in-the-middle attacks (y/n) yBy default, tokens are good for 30 seconds and in order to compensate for
possible time-skew between the client and the server, we allow an extra
token before and after the current time. If you experience problems with poor
time synchronization, you can increase the window from its default
size of 1:30min to about 4min. Do you want to do so (y/n) yIf the computer that you are logging into isn’t hardened against brute-force
login attempts, you can enable rate-limiting for the authentication module.
By default, this limits attackers to no more than 3 login attempts every 30s.
Do you want to enable rate-limiting (y/n) y
You notice this command might show a QR code at the top which you can download the Google Authenticator app on your phone to scan that code and it will setup your account automatically. If it doesn’t show a QR code it will show a link that will display the code.
You can now run openvpn and connect and the username is your shell user and if you set the password to test123 and google gives you a code of 847324, your password would be test123847324
Stripe CTF 2.0 Level 3
About
Here is a python level. They claim this one is more secure and it is a bit more but not really.
Hint Given
There really is no hint given other then in the code
Problem in the code
So take a look at line #86
query = """SELECT id, password_hash, salt FROM users
WHERE username = '{0}' LIMIT 1""".format(username)
cursor.execute(query)
So that is taking a username and pulling out data to see if the user/password combo is correct. The main issue is they aren't checking for invalid input. Like putting in quotes for the username.
Solution
So we are going to attack this with a SQL injection attack. Since there isn’t any validating of data that is sent in via the username we can put SQL in the username to make it pull out data that we want. So we can do this with a UNION statement. Pretty much our attack will be to union data we provide so it overrides the data that is in the database. So first we have to create a salted password to use. So lets first up python and do something like this
>>> import hashlib
>>> hashlib.sha256(“bob”+”bob”)
<sha256 HASH object @ 0x10045dc30>
>>> hashlib.sha256(“bob”+”bob”).hexdigest()
’4c26991843b5498e99ef26e6cf45c4eecd9e6890436f619054aaa8790b35967c’
So what we are doing is creating our own salted password to pass in via SQL injection to the app so it can compare with a password we send in via the form and a salt we are also injecting. So once we have that encrypted password and a known salt/password we will enter the following
As the username
‘ UNION SELECT id, ’4c26991843b5498e99ef26e6cf45c4eecd9e6890436f619054aaa8790b35967c’ AS password_hash, ‘bob’ AS salt FROM users where username=’bob’;–
As the password
bob
So that will take id,password_hash and salt and replace it in the code with what the database would return when select a user bob.
Now you have the next level’s password.
Stripe CTF 2.0 Level 2
About
This is another PHP level where they emulate a little social network where you can upload a image of to use for your profile. This level goes into what is wrong if you don’t force an output file type for uploaded content.
Hint Given
The hint really is that you can upload a file to use as an image.
Problem in the code
The problem in the code is really how they handle the upload. They just take a file and move it into the uploads/ directory and keep the name of the file you uploaded. Generally if you accept images, you’d want to convert anything uploaded into a jpeg.
Solution
So this is a pretty simple one. Create a file called like attack.php with the following contents in it.
<?php echo file_get_contents(“../password.txt”);
So that will put the file in uploads/attack.php so you can fire up your browser and hit the following page
https://level02-4.stripe-ctf.com/user-cnfowzkbbk/uploads/attack.php
It will spit out the contents of password.txt.
Stripe CTF 2.0 Level 1
About
In this level you are given a form where you have to “guess” the secret password to get the password to the next level. This level is in PHP and requires you to really looking at the code to figure out an attack point.
Hint Given
I don’t think there are any real hints in this level in the description.
Problem in the code
So here is the following section of code that has a problem. Take a look at line 13
extract($_GET);
This is where you know how to attack this level. The problem is that extract() takes an array and sets the key value to variables with the value set. This is not a good thing to do with $_GET/$_POST array since the user can set those and override any of the variables that are setup before the extract. This is line 12
$filename = 'secret-combination.txt';
$combination = trim(file_get_contents($filename));
This will take the contents of $filename and put it in $combination
Solution
So now that you know the weak spots. We want to attack the $_GET array. So we pass in a blank $filename and $attempt. So our query looks like
https://level01-2.stripe-ctf.com/user-xxxxxx/?filename=&attempt=
What that does is make $combination contain an empty string since the file contents of nothing is nothing. Then you are passing in combination on the $_GET array as nothing so it matches. The form wants to post but since it uses extract() to get the variable settings we can just attack it via $_GET and make the attack pretty easy.
Stripe CTF 2.0 Level 0
About
This is the first level of Stripe’s challenge. You start off in an app that stores secret passwords for users and you have an option to store a password or retrive a password.
Hint Given
So the following hint that is given on the page is as follows.
It turns out that the password to access Level 1 is stored within the Secret Safe. If only you knew how to crack safes…
It isn’t much of a hint since you know it’s stored there anyway probably
Problem in the code
So here is the following section of code that has a problem. Take a look at line 33
var query = 'SELECT * FROM secrets WHERE key LIKE ? || ".%"';
There is no checking for input provided by the user. There is also the following
db.all(query, namespace, function(err, secrets) {
Solution
This is an easy one if you know anything about sql. A % in sql is a wildcard. So just pass in a % for a secret you want to retrive and you will have the level 1 password shown.
Simple script to selectively remove emails from postfix’s queue
If you send out a lot of emails, the queue in postfix might be full of junk emails from people putting like bla@example.net as their email address. Now there could be other valid emails in there that you don’t want to remove due to their mail server down and postfix keeps trying for a set amount of time to re-send that email. So below is a simple script that you have to run as root that you can enter a search string as a paramater to remove emails from the queue