Authentication

This is a experiment of Information Security, about 7 exercises and challenges in this blog. May be a lot mistakes here, if you find it, please contact me.

Lab 4 : Authentication

Lab Environment Setup

Part A:Identity Forgery

There is a new service in the Touchstone web server: the transfer service. You can first register an account in the server and log in. You can now find the account page which will present the transferring interface, along with user name, login time, among other things.

Exercise 1 :

There are many bugs and vulnerabilities in the current utility for transferring money. Find as many bugs as you can. For now, just focus on bugs that an adversary can trigger by giving unanticipated values to the transfer page. Think carefully about what kinds of inputs an attacker might provide, and try them out by entering them on the transfer page. Please write down detail descriptions of your observation in bugs.txt. (You should find at least 4 different bugs.)

  • In getValues function: these key-values was parsed from the HTTP’s body and stored in the temp[16] array without boundary checking. If constructed a HTTP POST which included a lot of ‘user=liuchang&passwd=123&…’ strings, the banksv process will be crashed rapidly.

  • In handlePostLogin and handlePostRegister functions: there is a serious SQL injection attack here. Because when we execute these functions, the Db_checkUser Db_readBalance and Db_checkUserPasswd are called absolutely. However we can perform a SQL injection attack in these functions easily. For example, when a attack constructs a input about username likes : liuchang’;delete from user;, we will lost all user’s datas…

  • In handlePostTransfer function: there is no checking about the input of money filed, if given a negative number and transferring money to anyone, it will get more and more money constantly.

  • In handlePostTransfer function: if the transferring money is bigger than his account, it will result in a negative account… An important to note, it does not check whether the user exist in users.db.

  • In handlePostTransfer function: it doesn’t check the receiver and the sender. Now we use LiuChang account to transfer 100 $ to LiuChang, the result is funny, LiuChang will obtain 100 $ additionally. Let’s review these codes nearly.

1
2
3
4
5
6
int fromBalance = Db_readBalance (from);  // 100$
int newFromBalance = fromBalance - money; // 0$
int toBalance = Db_readBalance (to); // 100$
int newToBalance = toBalance + money; // 200$
Db_writeBalance (from, newFromBalance); // 0$
Db_writeBalance (to, newToBalance); // 200$

If the sender and the receiver is the same person, it will get more money constantly.

Exercise 2 :

Fix as many bugs as you can, from those you found above. Just keep your code as clean as possible. Also don’t forget to test your implementation after you fix the bugs.

For the first bug: when we get key-values form HTTP body, we should check the boundary of the temp array, If exceed the boundary, we should response a error to the browser and finish this request.

For the second bug: we should check these input filed, and exclude some special characters, such as ** , ; ? ** and so on.

For the third bug: we should check the input of money filed, and ensure that it is a positive number.

For the fourth bug: we should check the account and the receiver at first.



For the fifth bug: we have many ways to fix this bug. Simple to say, we just judge that whether the two person are the same. Surely, we can also make efforts in other aspects, when calculated the value of new balance, we should update the date base at once, just likes this :

1
2
3
4
5
6
int fromBalance = Db_readBalance (from);
int newFromBalance = fromBalance - money;
Db_writeBalance (from, newFromBalance);
int toBalance = Db_readBalance (to);
int newToBalance = toBalance + money; // a little stupid
Db_writeBalance (to, newToBalance);


Exercise 3 :

Read the source code of the login web page (in your browser), and the server’s source code. Make sure that you make it clear that how the server identify who is transferring.

At first, if a new client comes, the server will accept a fd and send it to the httpd process. Then the httpd begins to parse the client’s requests, GET requests are sent to filesv process, while POST requests will be sent to banksv process.

Before transferring money to others, banksv process parses the body of the request, and get the key-values from this body. If the first key is equal to Transfer, that’s to say, the user wants to transfer money to others. The banksv process identify who is transferring by the remaining key-values, such as transfer_from transfer_to and so on, and then start to update data base.

To this point, it should be clear to us that we can fool the server. That is: if we can construct a fake POST with some specific HTTP body attributes (what should they be?), and send the request to the server, we can fool the server that a victim is transferring money. And the server will perform the transfer!

Exercise 4 :

Try to construct a POST request about the money transferring, which steal money from some account if you know the victim’s account (it’s often the case). You can use browser.c or some tools, such as firebug to construct the request. Your request may look like this:

We can construct a HTTP POST request like this :

1
2
3
char *req ="POST / HTTP/1.1\r\nContent-Length: 74\r\n\r\n"
"submit=Transfer&transfer_from=abc&transfer_to=LiuChang&"
"transfer_money=100\r\n\r\n";

Exercise 5 :

Locate the code which handles the post request in handle.c, and add more code. You may find the response header Set-cookie: value useful. When one user transfers money, you should identify the user by cookie.

I am sorry about that I change a lot in this codes and ignore some design principles…

First of all, we should put forward such a problem about how to generate and save cookies ? In my way, I use a very large random integer as a cookie which can identify the unique user, may be repeated in very little probability, but who care. obtaining accurate values correspond to its user by guessing is impossible. I also add a filed named favorite number, it will describe clearly in Exercise 7, together they formed the cookie, like this :

1
username=random_number:favorite_number=user's input

Secondly, the server saves and obtains this value by reading cookie.txt file. When a new user registered, we will generate a cookie for it and save its other information into cookie.txt file as well. After registered, the server should response a HTTP headers likes this :

1
2
3
4
5
6
7
8
9
10
char * cookieFileOk = "HTTP/1.1 200 OK\r\nSet-Cookie: ";
int cookie = lookup_cookie( name );
int favorite_number = Db_getFavoriteNumber( name );
char send_cookie[128];
char info[512];
memset( send_cookie, 0, 128 );
memset( info, 0, 512 );
sprintf( send_cookie, "%s=%d:%s=%d", name, cookie, "Favorite_number", favorite_number );
sprintf( info, "%s%s\r\n\r\n", cookieFileOk, send_cookie );
write( fd, info, strlen(info) );

I use HttpFox to capture these POST headers, just like this :

Finally, when user wants to transfer money to others, it must provide its passport : cookie. If a attack doesn’t know the cookie exactly and just constructs a HTTP request likes Exercise 4, failure is no doubt. I will attach my codes to illustrate it more clearly.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#if 1
if( Db_checkUser( to ) <= 0 ) {
illegalInput( fd, "the transfer receiver does not exist !!!" );
return ;
}
if( m <= 0 ) {
illegalInput( fd , "illegal transfer account ! transfer money must be bigger than 0 !");
return ;
}
if( m > Db_readBalance(from) ) {
illegalInput( fd, "illegal transfer account ! transfer money must be less than your account !");
return ;
}
if( strcmp( from, to ) == 0 ) {
illegalInput( fd, "sender is the same as the reciever !" );
return ;
}
if( strcmp( cookie_value, real_cookie ) != 0 ) {
illegalInput( fd, "identify the cookie error! You are a bad guy..." );
return ;
}
#endif

An important to note: this cookie_value is parsed from the HTTP body in parseHeaders function, and was passed from Parse_parse to Handle_main, finally passed to handlePost function. It is a little awkward.

Part B:Packet Sniffing

Exercise 6 :

Using the Wireshark to steal the cookie, and then use the cookie to make fake POST request. Send the request to the server and transfer some one else’s money.

My account’s username is LiuChang. I use HttpFox to capture the cookie and construct a HTTP POST request to steal Alice account’s money. I will illustrate it in some pictures.
We steal Alice's cookie

1
2
3
4
5
char *req2 ="POST / HTTP/1.1\r\nContent-Length: 75\r\nCookie: Alice=876960:Favorite_number=123\r\n\r\n"
"submit=Transfer&transfer_from=Alice&transfer_to=LiuChang&"
"transfer_money=80\r\n\r\n";

write(sock_client,req2,strlen(req2));

Steal Alice's money successfully

Part C:Encryption

Encryption is the standard way to protect sensitive information from leaking. Encryption itself does not prevent interception, but denies the message content to the interceptor. In this part of the lab, you will explore how to use encryption to protect the packets.

Exercise 7 :

Encrypt the cookie. You should modify as least these files: index.html, handle.c, and dbutil.c etc…

As we known,Cookie is a small piece of data sent from a website and stored in the user’s web browser while the user is browsing it. It always saves user’s sensitive information and can be obtained by tools easily. In order to protect users’ sensitive information, we should encrypt these cookies.

In Exercise : 5, we use HttpFox to capture these Cookies and get user’s information easily. In order to defuse this , we need encrypt these cookies, and separate Login and Register modules.

First of all, we should drop old user’s table and re-build this table to add a number field which to save user’s favorite number. It just likes as the number of USB-key.

When a new user complete to register , we get its input about favorite number and generate a cookie. And we set this cookie into HTTP headers.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 static char *cookieFileOk =
"HTTP/1.1 200 OK\r\nSet-Cookie: ";

struct Cookie cookie;
srand(time(NULL));
int cookie_value = rand() % 1000000 + 99999 ; // generate a random cookie
memset( &cookie, 0, sizeof( struct Cookie) );
cookie.value = cookie_value;
strcpy( cookie.key, name );
fwrite( &cookie, sizeof( struct Cookie ), 1, fp ); // save it into cookie.txt
#if 1
char info[512];
char send_cookie[128];
memset( send_cookie, 0, 128 );
memset( info, 0, 512 );
sprintf( send_cookie, "%s=%d:%s=%d", name, cookie_value, "Favorite_number" , atoi( number ) );
encryption( send_cookie );
sprintf( info, "%s%s\r\n\r\n", cookieFileOk, send_cookie );
#endif
write(fd, info, strlen(info));

I use a simple algorithm to encrypt cookies…But the result is not bad.

1
2
3
4
5
6
7
8
static char * encryption( char * s ) {
char *p = s;
while( *p != '\0' ) {
*p = *p + 0x10;
p++;
}
return s;
}

When users want to transfer money to others, he must provide his favorite number(just likes USB-key)

The Login and Register modules are changed a little, but it does not make a difference…