Is Qualys getting paid for this excellent work, and if so, by who?
Is there a plan to do a serious audit of execle related code in OpenBSD?
As a longtime OpenBSD user, I gotta say that OpenSMTPD is the part of the system I'm least comfortable with from a security standpoint. Too many rewrites, mulligans, CVEs. Very little of the web howtos match the official documentation because there's so much churn, which by itself is a red flag. And even without a logic bug, I'm surprised execle was used at all here. It was unnecessary and naive. I'll be honest, I'm in the middle of transitioning from qmail to OpenSMTPD, and this bug is making me consider notqmail.
This RCE is trivial and super bad.
It is pretty ridiculous just how trivial and severe this is, indeed.
However, given the lower prevalence of OpenBSD, I'd be interested to know whether anyone has any data on whether this is being exploited in the wild.
I can't say I have any info on this subject, but having a group of people do stellar newsworthy offensive security research around widely used products is a good way to market your company for free and help drive sales for your security products.
It's only free from external cost though. The time for the staff at Qualys is (probably) not free. ;)
See:
https://en.wikipedia.org/wiki/Qualys
My guess is they use OpenBSD and this is part of 'give back'.
https://man.openbsd.org/syspatch
https://www.openbsd.org/errata66.html#p018_smtpd_tls
https://www.openbsd.org/errata66.html#p019_smtpd_exec
There is also a new portable release of OpenSMTPd - 6.6.2p1: https://www.mail-archive.com/misc@opensmtpd.org/msg04850.htm...
Of course, that’s partly because it’s so damn easy to exploit. Here’s what an exploit email actually looks like;
$ nc 127.0.0.1 25
220 obsd66.example.org ESMTP OpenSMTPD
HELO professor.falken
250 obsd66.example.org Hello professor.falken [127.0.0.1], pleased to meet you
MAIL FROM:<;sleep 66;>
250 2.0.0 O.k
...
That executes “sleep 66” as root.There simply must be a better way to parameterize calls to the MTA that contain remote/attacker provided input than exec’ing a shell. It should not all come down to being “absolutely sure” the input is escaped properly.
01 if (!A || !B) {
02 if (!B) {
03 fix(B);
04 return 1;
05 }
06 return 0;
07 }
08 return 1;
It’s interesting to think about the IF on Line 02.It could have read “if (A)” and that would have been correct, but IMO even better to write out “if (A && !B)” in case anything changes with the surrounding code later.
The problem of course is that “A” and “B” are expensive functions which you don’t want to call twice, and it just is so annoyingly verbose to have to assign booleans and then compare those...
You almost want to be able to write out a truth table based on calling the functions and then handling their return values. A kind of 2D switch statement;
switch (A, B) {
case 1,1:
return 1;
case 1,0:
fix(B);
return 1;
default:
return 0;
}
Does any language support a multi-dimensional switch statement like this?Hmm, maybe it’s not really any better that way either. The case statements are just not explicit enough.
It also usually helps to make the code more self-documenting
save_A = A;
save_B = B;
if (!A)
fix(A);
if (!B)
fix(B);
return (some_expression of save_A and save_B);match (a, b) with | (1, 1) -> 1 | (1, 0) -> (fix b); 1 | _ -> 0
*easy to sit here and armchair make claims of course. I've also only read this post and not the actual code so maybe there is reason for doing it how they did.
I'd add for writing the fix domain logic, probably most clear to fix it in one step, and then do the validation as a second step, instead of mixing the two. Minisculey less efficient but its much easier to follow if fixing and validating logic aren't mixed together.
However, as you yourself hinted, the cost (in C anyway) is giving up the short circuit - which might be expensive, or worse - might have unwanted side effects.
I'm not aware of a common language construct that would switch/match on both A and B, but defer executing B unless its value is actually needed.
if (A && B) {
return 1
else if (A && !B) {
fix(B)
return 1
else {
return 0
} 553 5.1.0 Sender address syntax errorThe code seems to go out of its way to avoid using the system() call to shell out, but then does exactly what system() would do.
Mail servers should run as nobody; mail box files are, in fact, world-writable, and their permissions should reflect that. Go ahead, critique the ergonomics of C's conditional expression syntax. But first, consider that this security model for a room full of terminals in the 1970s, where permission to accept connections on port 25 is also permission to format the hard disk, is totally nuts for a network-connected computer in the 2020s.
https://bonedaddy.net/pabs3/log/2014/02/17/pid-preservation-...
Of course, the reason they're invoking an external MDA is because this is classically how smptds and local mail delivery is separated. Is there a great reason for that? Not really. The MDA could be embedded in the smtpd.
Also, it's a bashism. It's not implemented by the OpenBSD's /bin/sh.
Also, I think nerds just sometimes hate admitting they like a thing that is a caricature of themselves. I hate to admit it, but I really liked Hackers, and thought it had a lot of relevant nerd stuff going on it, ditto on The Matrix :)
perl -00 -ne exit
unfortunately, the first line afterwards is also eaten. this is easily remedied by inserting one junk line though instead of a slide.I don't mean this sarcastically; I'm genuinely curious about the motivations. The only thing I can come up with is that it's slightly more annoying to free an array of strings than it is to free a single string in C. Is that plausibly the only motivation to involve a shell here?
First with the user authentication vulns [0], now this.
For those running OpenBSD boxes: the patch is available through syspatch, but you may need to change /etc/updateurl to an official OpenBSD CDN, since the patch is still fresh and not yet distributed to all mirrors.
I love OpenBSD and use it a lot. But this notion of C everywhere for everything is wrong.