| < | June 2007 | |||||
| Su | Mo | Tu | We | Th | Fr | Sa |
| 1 | 2 | |||||
| 3 | 4 | 5 | 6 | 7 | 8 | 9 |
| 10 | 11 | 12 | 13 | 14 | 15 | 16 |
| 17 | 18 | 19 | 20 | 21 | 22 | 23 |
| 24 | 25 | 26 | 27 | 28 | 29 | 30 |
Linux kernel debugging has always been a tough thing to do and requires pretty much a dedicated setup for regular effective debugging. But with the release of VMware 6, an inbuilt kernel debugger provided with it makes life pretty much easier in debugging the linux kernel for various requirements.
In case VMware 6 in Linux b0rks out for you with an error message:
neo@sauron ~ $ /opt/vmware/bin/vmware /opt/vmware/lib/vmware/bin/vmware: symbol lookup error: /opt/vmware/lib/vmware/lib/libvmwareui.so.0/libvmwareui.so.0: undefined symbol: _ZN3Gtk13RecentManager11get_defaultEvTry running VMware:
neo@sauron ~ $ VMWARE_USE_SHIPPED_GTK="yes" /opt/vmware/bin/vmware
To start with, do a regular installation of any GNU/Linux distro inside the
VMware and recompile the kernel with debugging options enabled. My debug
options looks something like this:
# # Kernel hacking # CONFIG_TRACE_IRQFLAGS_SUPPORT=y CONFIG_ENABLE_MUST_CHECK=y CONFIG_MAGIC_SYSRQ=y CONFIG_UNUSED_SYMBOLS=y CONFIG_DEBUG_KERNEL=y CONFIG_LOG_BUF_SHIFT=15 CONFIG_DETECT_SOFTLOCKUP=y CONFIG_DEBUG_BUGVERBOSE=y CONFIG_DEBUG_INFO=y CONFIG_DEBUG_VM=y CONFIG_FRAME_POINTER=y CONFIG_EARLY_PRINTK=y CONFIG_4KSTACKS=y CONFIG_DOUBLEFAULT=yMake sure you have turned on Use of Frame pointers while compiling the kernel from "Kernel Hacking" option during the kernel configuration. This will help gdb in the debugging process.
debugStub.listen.guest32 = "1"Now when you start your VMware guest OS, you will notice it is listening for a debug connection on 0.0.0.0:8832.
neo@sauron ~/hacks/kern-debug $ gdb GNU gdb 6.6 Copyright (C) 2006 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i686-pc-linux-gnu". (gdb) file ./vmlinux Reading symbols from /home/neo/hacks/kern-debug/vmlinux...done. Using host libthread_db library "/lib/libthread_db.so.1". (gdb) target remote 127.0.0.1:8832 Remote debugging using 127.0.0.1:8832 [New Thread 1] warning: shared library handler failed to enable breakpoint 0xc0102c58 in irq_entries_start () (gdb) bt #0 0xc0102c58 in irq_entries_start () #1 0xc010104e in default_idle () at include/asm/irqflags.h:57 #2 0xc01010ab in cpu_idle () at arch/i386/kernel/process.c:192 #3 0xc010033e in rest_init () at init/main.c:432 #4 0xc03fa737 in start_kernel () at init/main.c:620 #5 0x00000000 in ?? () (gdb)From here, you can do almost everything you would do in a normal user space application debugging.
(gdb) break do_execve Breakpoint 2 at 0xc014f117: file fs/exec.c, line 1133. (gdb) c Continuing. Breakpoint 2, do_execve (filename=0xc5ceb000 "/usr/bin/ls", argv=0xc015096e, envp=0xc4dc6f9c, regs=0xc4dc6fb8) at fs/exec.c:1133 1133 int retval; (gdb)Looks pretty neat!
posted at: 12:01 | path: / | permanent link to this entry
Wrote an exploit after a long time.. nothing interesting, but a simple stack overflow but initially proved to be a bit hard to trigger.
Started by taking a diff of snort-2.6.1.2 and snort-2.6.1.3 which instantly revealed the vulnerable code.
diff -Naur snort-2.6.1.2/src/dynamic-preprocessors/dcerpc/smb_andx_decode.c snort-2.6.1.3/src/dynamic-preprocessors/dcerpc/smb_andx_decode.c --- snort-2.6.1.2/src/dynamic-preprocessors/dcerpc/smb_andx_decode.c 2006-12-05 00:08:36.000000000 +0530 +++ snort-2.6.1.3/src/dynamic-preprocessors/dcerpc/smb_andx_decode.c 2007-02-17 13:00:11.000000000 +0530 @@ -31,6 +31,7 @@ #include#include "debug.h" +#include "bounds.h" #include "snort_dcerpc.h" #include "smb_structs.h" @@ -61,39 +62,80 @@ static void ReassembleSMBWriteX(SMB_WRITEX_REQ *writeX, u_int8_t *smb_data) { SMB_WRITEX_REQ temp_writeX; - unsigned int smb_hdr_len = (u_int8_t *)writeX - _dcerpc_pkt->payload; - unsigned int writeX_len = smb_data - (u_int8_t *)writeX; + u_int16_t smb_hdr_len = sizeof(SMB_HDR) + sizeof(NBT_HDR); + u_int16_t writeX_len = (u_int16_t)(smb_data - (u_int8_t *)writeX); + u_int32_t check_len; + int ret; + + check_len = (u_int32_t)smb_hdr_len + (u_int32_t)writeX_len + (u_int32_t)_dcerpc->write_andx_buf_len; . . . /* Mock up header */ - memcpy(&temp_writeX, writeX, writeX_len); + memcpy(&temp_writeX, writeX, sizeof(SMB_WRITEX_REQ)); temp_writeX.remaining = _dcerpc->write_andx_buf_len; temp_writeX.dataLength = _dcerpc->write_andx_buf_len;
After a bit of funtion call flow tracing and stuff.. got it right.
and oh, This helped a lot.
Thus, the following steps can reliably trigger the bug:
1. Send SMB TreeConnectAndX for \\X.X.X.X\IPC$
2. Send SMB NTCreateAndX
3. Send SMBWriteAndX + DCERPC Bind/Call with fraglength > payload (fragmented
PDU)
4. Send SMBWriteAndX with a pretty large ( > 16 or so) padding containing
ret and payload.
5. Bang! pwned.
For my testing purpose, I had nc listening on port 139 monitored by Snort
2.6.1.2 and the exploit connects to the port and blindly delivers the
payloads.
In practical senario, however its better to use a single TCP packet with
chained SMB headers triggering the bug with a single TCP packet as snort
runs in pretty stateless mode and doesnt really checks weather the packet
is a part of a valid TCP session.
In case anybody is interested:
Original advisory: http://www.iss.net/threats/257.html
PoC: http://eos-india.net/abhisek/codez/exploits/snort_dcerpc_pwn-v0.1.c
Users of vulnerable version of snort should try to upgrade to Snort 2.6.1.3 ASAP.
posted at: 17:45 | path: / | permanent link to this entry
Ruby-pcap is a pretty neat ruby binding for the pcap library.
While working with ruby-pcap, I found the lack of support for pcap_findalldevs
API in the binding..
so Here is a small patch to add it
into the ruby-pcap extension libary.
Here is the test case.
posted at: 18:24 | path: / | permanent link to this entry
Just came across after a very trivial change..
#include <stdio.h>
void crash()
{
char buf[20];
char *p = "\xff\xff\xff\xff\xff\xff";
sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x",
p[0],
p[1],
p[2],
p[3],
p[4],
p[5]);
printf("%s\n", buf);
}
int main()
{
crash();
return 0;
}
Compiled & Run
neo@sauron ~/documents/website/blog $ ./a.out ffffffff:ffffffff:ffffffff:ffffffff:ffffffff:ffffffff Segmentation fault neo@sauron ~/documents/website/blog $ gdb ./a.out GNU gdb 6.4 Copyright 2005 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i686-pc-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1". (gdb) r Starting program: /home/neo/documents/website/blog/a.out Failed to read a valid object file image from memory. ffffffff:ffffffff:ffffffff:ffffffff:ffffffff:ffffffff Program received signal SIGSEGV, Segmentation fault. 0x66666666 in ?? () (gdb) i r $eip eip 0x66666666 0x66666666 (gdb)Evident stack overflow!
neo@sauron ~/documents/website/blog $ diff ~/junk/crash.c ~/junk/crash2.c 6c6 < char *p = "\xff\xff\xff\xff\xff\xff"; --- > unsigned char *p = "\xff\xff\xff\xff\xff\xff"; neo@sauron ~/documents/website/blog $Compiled & Run
neo@sauron ~/documents/website/blog $ gcc ~/junk/crash2.c neo@sauron ~/documents/website/blog $ ./a.out ff:ff:ff:ff:ff:ff neo@sauron ~/documents/website/blog $
So how many apps are vulnerable like this?
and no, -fstack-protector probably wont fully protect you.. but ofcourse it will pretty much obscure the exploitation path, got to look into it.. apparently looked like a canary based protection..
GCC Stack protector adds following:
In procedure prolog:
0x0804842dIn procedure epilog:: mov %gs:0x14,%eax 0x08048433 : mov %eax,0xfffffff0(%ebp) 0x08048436 : xor %eax,%eax
0x080484c0: mov 0xfffffff0(%ebp),%eax 0x080484c3 : xor %gs:0x14,%eax 0x080484ca : je 0x80484d1 0x080484cc : call 0x8048330 <__stack_chk_fail@plt>
In procedure prolog, a 32 bit cookie is placed at (SFP - 8) which is checked with the original at %gs:0x14 which if not matched, __stack_chk_fail overflow handler is trigger thus abort()'ing. So apparently there is no way of corrupting saved EIP without corrupting this cookie and hence the protection.
Bypassable?Idea: I have a process (in memory execution context of a program.. remember?) that contains a function `do_something()`, can I at runtime patch this function or replace this function with a completely new externally supplied code? Patch GOT? Patch PLT? ptrace will help? google for ELF internals?
Thank god, feeling better :-)
posted at: 15:13 | path: / | permanent link to this entry
Weirdly enough, a small apparently elegant looking code working fine on my box and when statically compiled on my box works fine on all others boxens I tested. But trouble striked when of my colleague svn co'd my code and tried writing some plugin. The blue sky turned grey for me as it began crashing in bootstrapping of the app itself, apparently in a linked list implementation of circular queue.
After considerable amount of fiddling with..
neo@sauron ~/ROOT/work/v2/production $ cat > gdb break *(start_loader+116) command 1 p entry p entry->name p entry->func p entry->next p entry->prev continue end
(gdb) source ./gdb
Breakpoint 1 at 0x80ca831: file ra_loader.c, line 128.
(gdb) r
.
.
Breakpoint 1, 0x080ca831 in start_loader () at ra_loader.c:128
128 if(strncmp(entry->name, "bootstrap", strlen("bootstrap")) == 0)
{
$141 = (struct load_entry_t *) 0x828d8f0
$142 = 0x4fe1
$143 = (void (*)()) 0x4fe1
$144 = (struct load_entry_t *) 0xb7ee552c
$145 = (struct load_entry_t *) 0x0
Program received signal SIGSEGV, Segmentation fault.
0x080ca831 in start_loader () at ra_loader.c:128
128 if(strncmp(entry->name, "bootstrap", strlen("bootstrap")) == 0)
{
Initially looked like heap overflow somewhere which resulted in pointer overwrites, but after considerable effort, found its the same common flaw in pointer link/unlink of list blocks.
Lesson learned: try not to write up a quick queue/list implementation playing
with malloc'd ptrs, prefer using well tested ones.. probably `man queue`
(sys/queue.h) and rtfm helps..
http://www.gnu.org/software/libc/manual/html_node/Tracing-malloc.html#Tracing-malloc
posted at: 18:17 | path: / | permanent link to this entry
Finally recovered/configured my pyblosxom again.. after a long fight since I forgot most of the configuration and manual patches that I applied to my previous pyblosxom installation..
and btw.. since 2006 is almost over and I am pretty convinced that I have perfectly wasted this entire year..so, time to buckle up with renewed enthusiasm and stop being an idiot and actually write some code and feel better..
to start with..
Today's fortune:
The great pleasure in life is doing what people say you cannot do
posted at: 18:08 | path: / | permanent link to this entry
Back home after my first bangalore && FOSS.IN trip.. although the flight got
delayed by 2 hours or so due to heavy fog at bangalore airport but I returned
home safely near about 11:30am on 26th Nov (Sunday).. yeah missed the last day
and also ``Coffee @
Y!``.
posted at: 15:58 | path: / | permanent link to this entry
Everytime I enter my credit card information or important user/pass
information on web I always look for https with a certificate from some trusted
authority, one of the best practices I learned while working with _sekuwity_
people.
But seems like security research has reached such a stage that
software/automated security implementations are not enough to stay secure,
users must be security concious for close to good online security.
Most of the people I came across never really care about those irritating SSL
certificate warnings and just blindly click "OK" to go to their desiring page,
least they know someone might actually be redirecting traffic which is fairly
easy in a packet switched network and considering available tools like
Ettercap, I think its pretty easy..
Now consider this situation, somebody redirecting your traffic to their box
(at L2)
instead of the original gateway by manipulating the ARP cache of your OS (ARP
Poisoning) and ``The Man in the middle`` (between you and the gateway) has
a ruleset on his firewall like:
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j REDIRECT --to-port 31337So? all your https traffic will be redirected to his proxy on port 31337... then? you might establish an SSL session with the ``Man in The Middle`` rather than the real server.. so? possibilities are endless.
My ARP table is static..you cant poison me.. ok.. I will poison the person to whom you are connected :)
Now I have an idea, idea to implement a state based ARP inside the linux kernel. Basically idea is to make linux kernel stateful while processing ARP reponse packets. By default the kernel should be in non-accepting state for ARP response packets.. only when the kernel xmits an ARP packet to satisfy higher level networking requirements, it should go to accepting state for ARP response packet for a given IP-MAC(x) resolution and there should be timeout for switching back the kernel to non-accepting state if no packet arrives.
But again, this is just a very vague thought.. I really need get into the nitty-gritty details of the kernel network stack and the data structures and especially in the kernel land, its very easy to get lost and considering the stuff I am working on professionally these days, I dont think I will be able to do this in very near future..
posted at: 14:55 | path: / | permanent link to this entry
So finally got leave, plane tickets for bangalore..to attend Foss.in
Supposed to land on bangalore on 23rd Nov '06 @ 11:30am or so.. but cant be
that sure since its Air Deccan (the best affordable i could get at this
time).
Going to stay with my old time pal Hirosh in a place called ``Lakkasada`` or
something similar.
Hope to meet lots of people I talk to everyday on IRC (you know who you are)
:)
posted at: 14:30 | path: / | permanent link to this entry
Surely it is the biggest festival for bengalies.
This year I got the oppurtunity to try my hands on a Sony DSC-H2, so went for some hunting on Panchami along with my friends..
Time to go back boozing, in the mean time.. Click Here if you care to see some more Durga Puja 06 pics.
posted at: 11:05 | path: / | permanent link to this entry
Just managed to wake myself up after around 4 hours sleep, post Sankarpur(06) trip which ended today.
Normally I prefer mountains (gosh! am a trekking lover) over sea, but this sea side trip was pretty good especially with the awesome food and considerably fine alchohol.
Time to upgrade my flickr account and upload some pictures..
posted at: 18:30 | path: / | permanent link to this entry
May his soul rest in peace!!
posted at: 20:17 | path: / | permanent link to this entry
Oh yes, I am getting more and more impressed with Ruby.
Ruby being an apparently *very* simple and aesthetically pleasing language, but internally it is very complex in its implementation along with quite a few awesome and very intelligent hacks.
People interested in giving ruby a shot should surely start with the
following:
* About Ruby
* Ruby in 20 min
People interested in Ruby internals can take a look at "Ruby Hacking Guide".
Oh and before saying bye for the day, I would love to give away some fun.
A nice and *probably* usable ruby shell ;-)
#!/usr/bin/ruby
require 'readline'
class RShell
def initialize()
Signal.trap('INT') {
puts "Enter exit/quit to exit shell"
}
end
def unixcmd?(cmd = nil)
return nil unless cmd
paths = ENV["PATH"].split(':')
paths.each do |p|
file = "#{p}/#{cmd.split(' ',2)[0]}"
return true if File.exists? file
end
false
end
def run
loop do
cmd = Readline::readline("rsh #{ENV['PWD']}> $ ", true)
exit if cmd =~ /exit|quit/
if unixcmd? cmd
system(cmd)
else
begin
eval cmd
rescue
puts "Command not found"
end
end
end
end
end
RShell.new.run
posted at: 16:28 | path: / | permanent link to this entry
Recently I came across a class of people who are firm believers of relativity and the concept of reference frame. According to them there doesnt exists anything which is absolutely right or absolutely wrong. This discussion about right or wrong was going on over a dinner table along with drinks and most of us including the speaker was considerably drunk. So at that time I couldnt really find any vulnerability in this statement.
But later, with possibly better realization, I think we are living in a world
where there are certainly _very_ few people who truely grasp the concept of
relativity and that of reference frame, ofcourse me being in the majority.
Not that the word relativity here has
anything to do with "The Theory of
Relativity" technically, but conceptually
or psychologically it might have some relation which I couldnt figure out yet.
So its better to consider _generally_ right as right and _generally_ wrong as
wrong in most circumstances especially where it has something to do with the
interest of the _general_ else it might turn up into cheap hypocricy to hide
weakness/cheapness.
Although somewhat irrelevant, but I always used to think that I am a supporter of modern education/thinking but somehow now I think I am quite back dated from the point of view of mentality, because I am really sick and tired of artificial people trying to follow Dale Carnegie blindly.
posted at: 22:58 | path: / | permanent link to this entry
Libnids is an implementation of an E-component of Network Intrusion Detection
System. It emulates the IP stack of Linux 2.0.x. Libnids offers IP
defragmentation, TCP stream assembly and TCP port scan detection.
Libnids Homepage: http://libnids.sf.net
Such wonderful power of monitoring and uniquely identifying each TCP session if available in Ruby would make it more powerful, with this idea in mind I did the Ruby wrapper for libnids library last week.
The project page is located at: http://ruby-libnids.rubyforge.org
I upload testing codes at: http://ruby-libnids.rubyforge.org/testing/
An example script may look like this.
require 'libnids'
$l = 0
def callback(opts = nil, ss = nil)
return unless opts
case opts["nids_state"]
when NIDS::STATE_JUST_EST
str = String.new
str += "[NEW CONNECTION] #{opts['saddress']}:#{opts['sport']} --> "
str += "#{opts[ 'daddress']}:#{opts['dport']}"
when NIDS::STATE_DATA
str = String.new
str += "[DATA] #{opts['saddress']}:#{opts['sport']} --> "
str += "#{opts['daddress' ]}:#{opts['dport']} "
str += "[SEND: #{opts['server_data_len']}] [RECV:
#{opts['client_data_len']}]"
puts str
when NIDS::STATE_CLOSE, NIDS::STATE_RESET
str = String.new
str += "[CLOSE] #{opts['saddress']}:#{opts['sport']} --> "
str += "#{opts['daddress ']}:#{opts['dport']}"
end
end
$l = NIDS::Sniffer.new
$l.register_tcp(self, :callback)
$l.run
This thing is pretty new at the moment and tested only on a network of around 10 systems. I dont think it will be much efficient on high speed networks with large number of parallel TCP connections.
and oh, last but not the least, special thanks to Sumit Datta for making the webpage for http://ruby-libnids.rubyforge.org
posted at: 11:24 | path: / | permanent link to this entry
Finally seems like my blog is not junking up Planet India and I hope sankarshan and G0SUB wont be mad at me anymore regarding this, although its a seperate issue that they have many more things to be mad at me.
As usual the credit undoubtably goes to t3rmin4t0r for pointing me out the actual problem and also providing an appropriate fix.
The two things which I used for the fix are:
(a) t3min4t0r's hacked copy of pyfilemtime.py plugin for pyblosxom
(b) added lacking "<pubDate>$date $ti:00 $timezone</pubDate>"
in my story.rss pointed out by t3min4t0r
posted at: 10:55 | path: / | permanent link to this entry
From man prctl(2):
prctl() is called with a first argument describing what to do (with
values defined in <linux/prctl.h>),
and further parameters with a significance depending on the first one.
There is a bug/feature in sys_prctl() in kernel/sys.c exploiting which a
process can be forced to dump
its core in directories which should not be writable by the process.
Original Advisory: http://rhn.redhat.com/errata/RHSA-2006-0574.html
This vulnerability is fixed in the following patch:
http://www.kernel.org/diff/diffview.cgi?file=%2Fpub%2Flinux%2Fkernel%2Fv2.6%2Fincr%2Fpatch-2.6.17.3-4.bz2;z=2
My following hotfix should prevent exploitation of the above mentioned
vulnerability from publicly used techniques.
Hotfix: http://www.freeshell.in/~abhisek/linux_prctl_lkm.tar.gz
Some dmesg output while playing around with this hotfix.
neo@compaq blog $ dmesg | tail -n 11 Loading sys_prctl hotifx sys_call_table: 0xc0453780 Unloading sys_prctl hotfix Loading sys_prctl hotifx sys_call_table: 0xc0453780 Denied possible exploitation attempt [uid=1000 gid=100 pid=13805] Unloading sys_prctl hotfix Loading sys_prctl hotifx sys_call_table: 0xc0453780 Denied possible exploitation attempt [uid=1000 gid=100 pid=14008] Unloading sys_prctl hotfix neo@compaq blog $
Alright, another nice linux kernel bug got fixed. Kudoz to the RedHat Security
Team guys for finding such subtle bug/feature in the heart of the linux
kernel.
Now initially a lot of people had doubt weather this bug is actually
exploitable even after Paul Starzetz confirmed (made fun) of the bug and its
ease of exploitation.
Since I am documenting it for some unknown reason, I should mention clearly
for the poor people out there, THIS BUG _IS_ EXPLOITABLE FOR LOCAL PRIVILEGE
ESCALATION and rm -rf /& is quite possible in this case.
For those who believe in ``seeing is believing'' can take a look at:
http://www.freeshell.in/~abhisek/rs_prctl_kernel.c
and dotslah their way to some fun.
References:
http://www.kernel.org/diff/diffview.cgi?file=%2Fpub%2Flinux%2Fkernel%2Fv2.6%2Fincr%2Fpatch-2.6.17.3-4.bz2;z=2
http://www.securityfocus.com/bid/18874
posted at: 23:31 | path: / | permanent link to this entry
Software doesn't just appear on the shelves by magic. That program
shrink-wrapped inside the box along with the indecipherable manual and
12-paragraph disclaimer notice actually came to you by way of an elaborate
path, through the most rigid quality control on the planet. Here, shared
for the first time with the general public, are the inside details of the
program development cycle.
1. Programmer produces code he believes is bug-free.
2. Product is tested. 20 bugs are found.
3. Programmer fixes 10 of the bugs and explains to the testing department that the other 10 aren't really bugs.
4. Testing department finds that five of the fixes didn't work and discovers 15 new bugs.
5. See 3.
6. See 4.
7. See 5.
8. See 6.
9. See 7.
10. See 8.
11. Due to marketing pressure and an extremely pre-mature product announcement based on overly-optimistic programming schedule, the product is released.
12. Users find 137 new bugs.
13. Original programmer, having cashed his royalty check, is nowhere to be found.
14. Newly-assembled programming team fixes almost all of the 137 bugs, but introduce 456 new ones.
15. Original programmer sends underpaid testing department a postcard from Fiji. Entire testing department quits.
16. Company is bought in a hostile takeover by competitor using profits from their latest release, which had 783 bugs.
17. New CEO is brought in by board of directors. He hires programmer to redo program from scratch.
18. Programmer produces code he believes is bug-free....
THE GRAPHICAL REPRESENTATION
posted at: 20:38 | path: / | permanent link to this entry
Today while testing my shellcode, I suddenly had a weird idea. I used to think the mainline 2.6 branch of linux kernels from kernel.org is pretty secure these days and application level exploitation over these latest linux kernels are extinct concept because of the secure by default memory permissions.
Well, lets get going in my attempt to dig deeper into linux memory management
and paging implementations.
Currently I am running Gentoo with 2.6.14 on my laptop. The memory mappings as
available from /proc looks something like this:
note: I am using the gentoo-sources kernel from portage without any hack or
external patches like GrSecurity/PaX or SELinux/ExecShield.
neo@compaq ~ $ cat /proc/self/maps 08048000-0804c000 r-xp 00000000 03:06 38646 /bin/cat 0804c000-0804d000 rw-p 00003000 03:06 38646 /bin/cat 0804d000-0806e000 rw-p 0804d000 00:00 0 [heap] b7eb8000-b7fc1000 r-xp 00000000 03:06 87733 /lib/libc-2.3.5.so b7fc1000-b7fc2000 ---p 00109000 03:06 87733 /lib/libc-2.3.5.so b7fc2000-b7fc3000 r--p 00109000 03:06 87733 /lib/libc-2.3.5.so b7fc3000-b7fc6000 rw-p 0010a000 03:06 87733 /lib/libc-2.3.5.so b7fc6000-b7fc9000 rw-p b7fc6000 00:00 0 b7fe7000-b7ffc000 r-xp 00000000 03:06 87744 /lib/ld-2.3.5.so b7ffc000-b7ffd000 r--p 00014000 03:06 87744 /lib/ld-2.3.5.so b7ffd000-b7ffe000 rw-p 00015000 03:06 87744 /lib/ld-2.3.5.so bf8e7000-bf8fc000 rw-p bf8e7000 00:00 0 [stack] ffffe000-fffff000 ---p 00000000 00:00 0 [vdso] neo@compaq ~ $
Looking at the memory mappings, its quite apparent that there doesnt exists any segment with both write ("w") _AND_ execute ("x") permission. I have been looking into such memory mappings for quite some time now, assuring my paranoid mind that I am quite secure, atleast from arbitrary code injection/execution level exploitation techniques.
Due to some reason and unable to find out the technical reasonings for some
unexpected behaviour, I started playing with it.
The following code can be used to test the default memory permissions
implemented by my kernel.
#include <stdio.h>
/*
BITS 32
GLOBAL _start
_start:
call getString
db "Hello World",0x0a,0x00
getString:
pop ecx
mov edx, 12
mov ebx, 1
mov eax, 4
int 0x80
xor eax,eax
xor ebx, ebx
inc eax
int 0x80
*/
static char code[] =
"\xe8\x0d\x00\x00\x00\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64"
"\x0a\x00\x59\xba\x0c\x00\x00\x00\xbb\x01\x00\x00\x00\xb8\x04\x00"
"\x00\x00\xcd\x80\x31\xc0\x31\xdb\x40\xcd\x80";
int main(int argc, char **argv)
{
int (*funct)();
char temp;
funct = (int (*)()) code;
printf("code is at 0x%x\n",&code);
printf("sizeof code is 0x%x bytes\n",sizeof(code));
printf("Checking read/write on code's segment\n");
temp = code[10]; /* Read works */
code[10] = 0xff; /* Write works */
code[10] = temp; /* Restore the byte */
printf("All works\n");
printf("Executing code\n\n");
(int)(*funct)();
}
To my surprise (yeah may be I was wrong) I have results like this.
neo@compaq ~/CVSROOT/ $ gcc helloworld.c neo@compaq ~/CVSROOT/ $ ./a.out code is at 0x80496c0 sizeof code is 0x2c bytes Checking read/write on code's segment All works Executing code Hello World neo@compaq ~/CVSROOT/ $
Yes code was actually rwx (Readable,Writable, Executable).
Looking into address of ``code'' (0x080496c0), it appears to be in the
.data segment which is supposed to be non-executable as per /proc/{pid}/maps.
0x080496a0->0x080496ec at 0x000006a0: .data ALLOC LOAD DATA HAS_CONTENTS
http://www.adamantix.org/paxtest/
Some links for Linux kernel security stuff
http://www.grsecurity.net http://pax.grsecurity.net http://www.nsa.gov/selinux/index.cfm http://www.redhat.com/f/pdf/rhel/WHP0006US_Execshield.pdf
posted at: 19:06 | path: / | permanent link to this entry
Once upon a time, not so long ago but quite some time ago, when I was doing my
first year graduation, somebody asked me something about bubble sort (yes
probably the most simple sorting algorithm) and I remember I could not
answer. Well, now here is my little try at the question posed to me quite some
time ago...
;;
;; BUBBLE SORT IN 32BIT x86 ASSEMBLY
;; SHOULD WORK OVER LINUX KERNEL
;; THIS MADNESS IS DEDICATED TO THE GRAND OCCASSION OF 2nd JUNE 2006
;; HAIL PEPSI
;; MAY YOU AND I REST IN PEACE SOMEDAY
;;
;; POSITION INDEPENDENT ASSEMBLY COMPONENT
;; YOU CAN MAKE A RELIABLE SHELLCODE OUT OF THIS
;; EVIL HAXORZ CAN USE PWNED BOX FOR DOING BUBBLE SORT
;;
BITS 32
GLOBAL _start
%define FD_STDOUT 1
%define FD_STDIN 0
%define __NR_READ 3
%define __NR_WRITE 4
%define __NR_EXIT 1
_start:
push ebp
mov ebp, esp
sub esp, 4
call helloStr
db "Enter the number of elements to sort: ",0x00
helloStr:
pop ecx
push ecx
call sub_PrintStr
call sub_ReadDword
mov ecx, eax
mov dword [ebp - 4], ecx
elementReaderLoop:
call getAskString
db "Enter number: ",0x00
getAskString:
pop esi
push ecx
push esi
call sub_PrintStr
pop esi
pop ecx
push ecx
call sub_ReadDword
pop ecx
push eax
loop elementReaderLoop
mov eax, dword [ebp - 4]
push eax ; Number of elements to sort
int3
call sub_BUBBLES
int3
call sub_Exit
; sub_BUBBLES(n, A[n])
; This procedure will sort A[n] in descending order using the bubble sort algorithm
; The _list_ A is modified _in_ _place_ for sorting
sub_BUBBLES:
push ebp,
mov ebp, esp
call startMsg
db "Bubble sort start..",0x0a,0x00
startMsg:
pop ecx
push ecx
call sub_PrintStr
mov ebx, [ebp+8]
dec ebx
xor ecx, ecx
add ebp, 12 ; EBP now points to param array base
bubbleSortLoop1:
mov edx, ecx
bubbleSortLoop2:
pusha
mov eax, [ebp + edx * 4]
mov ebx, [ebp + ecx * 4]
cmp eax, ebx
popa
jl swap
jmp loop2
swap:
push dword [ebp + edx * 4]
push dword [ebp + ecx * 4]
pop dword [ebp + edx * 4]
pop dword [ebp + ecx * 4]
loop2:
inc edx
cmp edx, ebx
jl bubbleSortLoop2
inc ecx
cmp ecx, ebx
jl bubbleSortLoop1
call endMsg
db "Bubble sort ends..",0x0a,0x00
endMsg:
pop ecx
push ecx
call sub_PrintStr
sub ebp, 12 ; Restore EBP
mov esp, ebp
pop ebp
ret
; sub_Strlen(str_ptr)
sub_Strlen:
push ebp
mov ebp, esp
mov edi, [ebp+8]
xor ecx, ecx
xor al, al
not ecx
cld
repne scasb
not ecx
dec ecx
mov eax, ecx
mov esp, ebp
pop ebp
ret
; sub_PrintStr(str_ptr)
sub_PrintStr:
push ebp
mov ebp, esp
mov eax, [ebp+8]
push eax
call sub_Strlen
mov ebx, FD_STDOUT
mov ecx, [ebp+8]
mov edx, eax
mov eax, __NR_WRITE
int 0x80
mov esp, ebp
pop ebp
ret
; sub_PrintRaw(data_ptr, size)
sub_PrintRaw:
push ebp,
mov ebp, esp
mov ebx, FD_STDOUT
mov ecx, [ebp+8]
mov edx, [ebp+12]
mov eax, __NR_WRITE
int 0x80
mov esp, ebp
pop ebp
ret
; sub_ReadDword()
sub_ReadDword:
push ebp
mov ebp, esp
sub esp, 16
mov ebx, FD_STDIN
lea ecx, [ebp - 16]
mov edx, 16
mov eax, __NR_READ
int 0x80
xor ecx, ecx
lea esi, [ebp - 16]
endFinderLoop:
cmp byte [esi + ecx], 0x0a
je endFinderLoopEnd
inc ecx
jmp endFinderLoop
endFinderLoopEnd:
mov byte [esi + ecx], 0x00
dec ecx
xor eax, eax
xor edx, edx
atoiLoop:
xor ebx, ebx
add bl, byte [esi + edx]
sub bl, 0x30
push edx
push 10
mul dword [esp]
add eax, ebx
add esp, 4
pop edx
cmp edx, ecx
je atoiLoopOut
inc edx
jmp atoiLoop
atoiLoopOut:
mov esp, ebp
pop ebp
ret
sub_Exit:
mov eax, __NR_EXIT
xor ebx, ebx
int 0x80
Thank You and bye bye World for today
posted at: 00:00 | path: / | permanent link to this entry