Security by obscurity fails again
-
@flabdablet said in Security by obscurity fails again:
...relative to the start of the binary. You don't know their actual load address ahead of time, which you'd need to do in order to work out what to stuff into your stack smashing buffer payload in order to RET to one.
And also relative to code of the current function being executed. And since there's an indirect relative CALL instruction, that's all you need. The base load address of the current binary is just as irrelevant as all the rest of them.
-
@flabdablet
Hm, OK. You'd lose a register, because you cannot do stack pointer relative addressing anymore, and you have yet another memory region apart from stack and heap, which is somewhere in the middle (?), but it might actually work. I'll have to think about that for a bit.
-
@asdf You'd only need to know that if you had to use a CALL to an absolute address. But there is also a relative CALL instruction, which means that as long as you stay within the same module, the base load address is irrelevant.
Seriously, do you even ASM bro?
-
@masonwheeler said in Security by obscurity fails again:
And also relative to code of the current function being executed.
So? To get that address and use it, you'd still need read and write access to the stack inside the same function, which calls an external library, which is highly unrealistic. And even if you have that, you'd need to use the code of the function itself to read the call instruction. Good luck with that.
-
@asdf said in Security by obscurity fails again:
So? To get that address and use it, you'd still need read and write access to the stack inside the same function, which calls an external library, which is highly unrealistic. And even if you have that, you'd need to use the code of the function itself to read the call instruction.
...huh?
I have no idea how you reached that conclusion, any of it.
-
@masonwheeler said in Security by obscurity fails again:
since there's an indirect relative CALL instruction, that's all you need.
Return-oriented code only works via absolute addresses.
Until somebody else's code has jumped to an absolute return address you overwrote in the stack using your crafted extra-length buffer content, your indirect relative CALL doesn't get a chance to execute.
-
@flabdablet https://blogs.msdn.microsoft.com/oldnewthing/20050421-28/?p=35833
Apparently the Itanium had two stacks, one for data, and one for registers (including return addresses).
-
@masonwheeler said in Security by obscurity fails again:
I have no idea how you reached that conclusion, any of it.
To get the address of any code, you need to read the return address. To jump to arbitrary code, you'll need write access. Due to NX, you cannot just jump to something on the stack, you need to use the code in the text segment whose location you identified.
-
@asdf said in Security by obscurity fails again:
you cannot do stack pointer relative addressing anymore
No, you'd end up using frame-pointer-relative addressing instead, which is exactly what happens now for code compiled without -fomit-frame-pointer.
Yes, it costs a register, but that's a register that convention has long dedicated to that very purpose for reasons I've never really understood. It might be that back at the dawn of time when all this stuff was still being invented, there was a CPU in common use that didn't allow SP-relative indexed addressing?
-
@masonwheeler said in Security by obscurity fails again:
@asdf You'd only need to know that if you had to use a CALL to an absolute address. But there is also a relative CALL instruction, which means that as long as you stay within the same module, the base load address is irrelevant.
Most exploits don't let you execute arbitrary instructions of your choosing in the first pass. As mentioned above, you start off by overwriting a return address on the stack, which is absolute. (Or possibly a function pointer somewhere, but these are absolute too.)
If you were able to inject arbitrary instructions from the get go, you can skip the whole mess and just do a
syscall
.
-
@cvi Yeah, the Itanium was ahead of its time in a lot of ways. It basically failed due to being difficult to write a compiler for. If Intel had provided a bytecode format to target and their own compiler to turn that into Itanium assembly (writing compilers targeting their own architecture is something Intel is very good at) it would probably have gone a lot better for them.
-
@cvi said in Security by obscurity fails again:
the Itanium had two stacks
as did the 6809, as does almost any architecture with more-or-less general-purpose registers. Even the 8086 had SP and BP.
FORTH actually implements the dual-stacks part of this pattern, for what it's worth; the evaluation and return stacks are completely separate (they kind of have to be, because FORTH doesn't have local variables as such, just an evaluation stack). And FORTH runs on 6502.
-
@flabdablet said in Security by obscurity fails again:
It might be that back at the dawn of time when all this stuff was still being invented, there was a CPU in common use that didn't allow SP-relative indexed addressing?
I'd rather say it was considered too hard for early compilers to keep track of where the SP currently is, with all the push and pop instructions necessary to spill registers. FP-relative addressing is easy to get right, SP-relative addressing is hard.
-
@masonwheeler Indeed. Or at least provided a non-crappy compiler ... at least from what I've heard, they didn't really have the required compiler-tech themselves when they first launched the Itanium.
-
@asdf said in Security by obscurity fails again:
SP-relative addressing is hard
Error-prone for an assembly programmer, maybe. For a compiler, not so much.
-
@flabdablet said in Security by obscurity fails again:
Hard for a compiler, not so much.
We're talking about the time when x86 was invented. Compilers were a lot crappier back then. Maybe they didn't trust the people writing them? :p
-
@asdf Even on the 8086, where SP and BP addressing always use the SS segment by default, you could run split call and data stacks with the data stack growing upward. You'd just start both SP and BP pointing somewhere inside the SS (probably much nearer the bottom than the top) and let the SP call stack grow downward per 8086 CALL/RET convention and the BP data stack grow upward with BP manipulation under manual control.
The 8086's ENTER and LEAVE instructions are not faster enough than by-hand BP manipulation to be compelling choices.
Anyway. This scheme has been completely fucking obvious to me for fucking decades at this point but as far as I know nobody's doing it in any production compiler, so I'm guessing there's some fundamental flaw that I'm just not seeing.
-
@flabdablet OK, I clearly don't have enough onions on my belt.
-
@flabdablet said in Security by obscurity fails again:
More on this from Tired.com.
the research team, known as VUSec, released a demonstration video showing it running in a Firefox browser.
I blame @Lorne-Kates
-
@masonwheeler said in Security by obscurity fails again:
Seriously, do you even ASM bro?
BTW: By now, I'm asking myself the same thing. Some of what you're saying makes sense, but I still have no idea how your proposed exploit would work. You cannot execute an instruction that reads the instruction pointer only because you have write access to the stack. That's what the NX bit prevents.
-
@accalia said in Security by obscurity fails again:
@HardwareGeek said in Security by obscurity fails again:
@RaceProUK said in Security by obscurity fails again:
@CreatedToDislikeThis said in Security by obscurity fails again:
How'd that get 16 downvotes and counting?
Rust haters, probably.
Proposal for a new language: Galvanized
i'd program in that.
:id_hit_that.png:
-
@Polygeekery said in Security by obscurity fails again:
@accalia said in Security by obscurity fails again:
@HardwareGeek said in Security by obscurity fails again:
@RaceProUK said in Security by obscurity fails again:
@CreatedToDislikeThis said in Security by obscurity fails again:
How'd that get 16 downvotes and counting?
Rust haters, probably.
Proposal for a new language: Galvanized
i'd program in that.
:id_hit_that.png:
:i-hit-it-with-my-axe.avi:
-
@asdf You don't need to read the instruction pointer, because you already know where you are, because you already have your own copy of the binary. (See: relative locations, above.)
-
@masonwheeler I think you're gonna need to post a proof-of-concept or something.
-
@masonwheeler said in Security by obscurity fails again:
you already have your own copy of the binary
...which, given any non-half-assed ASLR loader (no idea if Windows has such a loader) will be loaded at an unpredictable absolute location.
-
@flabdablet ...which is 100% irrelevant when you can use relative addressing, as I have pointed out multiple times already. Why do you keep coming back to this?!?
-
@masonwheeler said in Security by obscurity fails again:
You don't need to read the instruction pointer, because you already know where you are, because you already have your own copy of the binary. (See: relative locations, above.)
How does knowing the current line in the binary help you if you don't know where to find it in memory? You're still not making sense. Yes, I know where to find interesting code relative to the instruction pointer, but that doesn't help me at all.
-
@masonwheeler said in Security by obscurity fails again:
which is 100% irrelevant when you can use relative addressing
Do you mean the addressing mode of the MMU? How is that relevant when you're not yet at the point where you can execute arbitrary instructions?
Could you maybe explain WTF you're trying to tell us here?
-
@masonwheeler said in Security by obscurity fails again:
which is 100% irrelevant when you can use relative addressing
...which, in order to launch sploit code by overwriting a return address in the stack with a buffer overflow, you can't, as I have pointed out multiple times already. Why do you keep coming back to this?!? :-)
-
@HardwareGeek said in Security by obscurity fails again:
Proposal for a new language: Galvanized
Rejected. Too many syllables.
-
@masonwheeler said in Security by obscurity fails again:
So you use the location of the fixup in exactly the same way
I thought the location of the fixup is supposed to be part of what is randomized by ASLR?
In every one of your proposed attacks you're assuming you can reliably read/call some space in memory and have it do a specific thing, which is supposedly exactly what ASLR is there to prevent. You've convinced yourself that you've theoried your way out of ASLR, but not in reality as far as I can tell.Besides, isn't your idea more or less what the article is about, a hack where you really can find the location of the "fixup" reliably via the side channel?
-
@asdf No, I mean that CALL and JMP instructions can be relative, and often are.
-
@dcon said in Security by obscurity fails again:
@HardwareGeek said in Security by obscurity fails again:
Proposal for a new language: Galvanized
Rejected. Too many syllables.
HotDip?
-
@masonwheeler But how are you going to overwrite CALL or JMP? The text segment is read-only and you still don't know where it actually is.
-
@darkmatter said in Security by obscurity fails again:
I thought the location of the fixup is supposed to be part of what is randomized by ASLR?
No, the value of the fixup is what is randomized by ASLR. The location of it can not be, because the binary needs for it to be at a known location.
In every one of your proposed attacks you're assuming you can reliably read/call some space in memory and have it do a specific thing, which is supposedly exactly what ASLR is there to prevent.
Nope. Again, location vs. value.
-
@asdf said in Security by obscurity fails again:
The text segment is read-only
but clever people like me, who talk loudly in restaurants, see this as a deliberate ambiguity, a plea for understanding in a mechanized world. The points are frozen, the beast is dead. What is the difference? What indeed is the point? The point is frozen, the beast is late out of Paddington. The point is taken. If La Fontaine's elk would spurn Tom Jones the engine must be our head, the dining car our oesophagus, the guard's van our left lung, the cattle truck our shins, the first-class compartment the piece of skin at the nape of the neck and the level crossing an electric elk called Simon. The clarity is devastating. But where is the ambiguity? It's over there in a box. Shunt is saying the 8.15 from Gillingham when in reality he means the 8.13 from Gillingham. The train is the same only the time is altered. Ecce homo, ergo elk. La Fontaine knew his sister and knew her bloody well. The point is taken, the beast is moulting, the fluff gets up your nose. The illusion is complete; it is reality, the reality is illusion and the ambiguity is the only truth. But is the truth, as Hitchcock observes, in the box? No there isn't room, the ambiguity has put on weight. The point is taken, the elk is dead, the beast stops at Swindon, Chabrol stops at nothing, I'm having treatment and La Fontaine can get knotted.
-
@flabdablet You're talking about the virtues of NX, which I agreed is a useful exploit-mitigation tool, not about the virtues of ASLR. Please keep the strawman population down.
-
@masonwheeler said in Security by obscurity fails again:
You're talking about the virtues of NX, which I agreed is a useful exploit-mitigation tool, not about the virtues of ASLR. Please keep the strawman population down.
So you're talking about an attack in a virtual fantasy world in which ASLR is present, but NX is not?
-
@masonwheeler said in Security by obscurity fails again:
the binary needs for it to be at a known location
The loader needs to know where it is. Once the loader has fixed up the binary, the binary doesn't need to know shit. Or is the Windows ASLR implementation even more completely stupid than I thought?
-
@flabdablet he has theoried himself right past what ASLR does... which makes it no surprise that he would then find ASLR to be completely useless.
-
as best as I can tell, the proposed masonwheeler hack goes
- thing a thing
- overflow thing
- use overflow to cause program to call some sys function you know where to call
somewhere in there is steps 3 & 4, which is what ASLR made impossible (previously, apparently)
Maybe his idea is that you can get the program to call things it already had ability/knowledge to call? that i suppose counts as an exploit, but not a particularly useful one, except maybe on people that run every app as administrator?
-
@masonwheeler said in Security by obscurity fails again:
You're talking about the virtues of NX
No, I'm talking about how the hell you actually get your buffer-overflow-sploiting-sploit to actually get executed. All NX means is that the code your overwritten return address points to (absolutely) can't be supplied inside the sploit itself; you have to use return-oriented programming, which involves constructing a list of absolute addresses that the CPU will treat as the targets for subsequent RET instructions.
Whether you're using ROP or a simple shellcode that NX would defeat, the first instruction your sploit is going to run is reached when the function whose stack frame you just smashed gets around to executing its RET. And there's no relative RET. So the address you write into the stack frame has to be an absolute address. Which means you either need to know the absolute (not relative) address of your own shellcode in the no-NX case, or the absolute (not relative) address of some piece of existing gadgetable code in the ROP case.
-
OK, so I've been sorta half-following this argument, and I'll be honest, it's no clearer to me just what's going on than it was before. So, I just want to make sure I've got my understandings straight.
So, we have these two things, ASLR and NX (DEP on Windows). Together, they mitigate a class of exploits, and they do so in different ways. NX is easy to understand: it's a flag on a page that says
No eXecute
. ASLR is a bit more complicated, as it's all about moving executable modules around in memory at load time to prevent addresses being predictable.The effectiveness of ASLR depends on three things: entropy of randomness, size of address space, and just how many things are relocated by ASLR. The first two are simple enough to understand, but the third is where this little argument is centred.
Am I right so far?
-
@RaceProUK said in Security by obscurity fails again:
Am I right so far?
Sounds good. Except that nobody can figure what what @masonwheeler is even arguing.
Also, side note: ASLR is not only ineffective, but completely useless if it cannot relocate absolutely everything. Which is why it's important to compile your programs with the -pie switch. (Which may or may not be on by default, depending on how your GCC/Clang binaries were compiled. Don't ask me what the Visual Studio equivalent is, because I have no clue.)
-
@darkmatter hell he convinced me to theory myself past the ASLR too in arguing with him. damnit.
if the program is chunked into different chunkies when loaded and the memory addresses are randomized, where exactly are you planning to buffer overflow TO that you expect you can have it get executed in the first place?which now sounds a lot like @flabdablet 's point, so i think i am agreeing with that.
-
BTW: Back to the original topic:
(I know, )Does this technique actually help bypass ASLR if you don't have a sandboxed, JIT-compiled programming language available? Because it sounds like this only works in a browser or virtual machine.
-
@asdf said in Security by obscurity fails again:
Sounds good.
Excellent
As we know, ASLR works by randomising the base addresses of loadable modules. This will almost certainly change the targets of any absolute jumps, so those need to be patched, a task done by the loader before the module becomes part of the process, as it were, and it's done in a way that leaves the process itself completely unaware ASLR has even happened.
It's at this point I hit a of understanding. It seems to me that the modules are each relocated as a monolithic whole. However, is this actually what happens, or is the module split into its sections, like
.text
,.data
, and.imports
(I've probably got one or more of those wrong, but it'll work as an example), and each section is subject to ASLR separately?
-
@asdf said in Security by obscurity fails again:
Does this technique actually help bypass ASLR if you don't have a sandboxed, JIT-compiled programming language available? Because it sounds like this only works in a browser or virtual machine.
My understanding is that it works just as well natively as in JS:
We have implemented AnC natively and in JavaScript! We use our native version to establish that MMU’s signal can be observed on 22 different microarchitectures and use our JavaScript version to find code and heap pointers in Firefox and Chrome browsers.
-
@RaceProUK said in Security by obscurity fails again:
However, is this actually what happens, or is the module split into its sections, like .text, .data, and .imports (I've probably got one or more of those wrong, but it'll work as an example), and each section is subject to ASLR separately?
The details probably depend on the implementation. However, it would make sense to relocate each part independently. Especially the PLT (which tells the program where to find library functions) should be relocated separately from the code, since having it at a known address relative to the return address of a vulnerable function might be risky.
-
@CreatedToDislikeThis said in Security by obscurity fails again:
My understanding is that it works just as well natively as in JS:
That's obvious, but you need a sandboxed environment, right? Which means, an exploit using corrupt video files cannot use it? (Unless that video file format uses an embedded programming language, which would be very scary.)