Hunting Bot Networks

Noam Rotem and Yuval Adam

Bots / Avatars / Sockpuppets

Methodology

  • Crowd-source suspicious accounts
  • Identify suspicious clusters
  • Manual and automated research

Recap - The Turkish Network

Content

Suspicious Metadata

Cultural Inaccuracies

False Flag

Suspicious Cluster

Organic Network

Media References

Content

The Turkish Connection

Results

  • Twitter disclosure
  • 142 accounts suspended

Kingdom Salvation

כנסיית האל הכל יכול

Israeli Girls Network

Israeli Girls Network

  • Same naming patterns
  • All accounts created within 4 hours
  • Still active...

Journalists at Risk

Fake News Campaign

Fake News Campaign

One-time Account

  • Old account
  • Wiped history clean
  • Re-branded as a "legit" account
  • Target journalists with DMs and @s

Social Graph Mismatch

Tech Infrasctructure

Twitter Data Collection

  • Python
  • PostgreSQL
  • SQLAlchemy
  • Celery

Lifecycle

  • Twitter API calls
  • Response serialization and storage
  • Tagging (for research)
  • CSV and XLS exports
  • Web-based dashboard
  • Gephi for graph visualization

מודל לדוגמה

class User(Base):
    __tablename__ = 'users'

    id = Column(String(20), primary_key=True)
    name = Column(String(15), nullable=False)
    full_name = Column(Text)
    description = Column(Text)
    created = Column(DateTime)
    location = Column(Text)
    protected = Column(Boolean)

    followers_count = Column(Integer)
    friends_count = Column(Integer)
    favourites_count = Column(Integer)
    statuses_count = Column(Integer)
    listed_count = Column(Integer)

    imported = Column(DateTime(timezone=True), default=func.now())
    updated = Column(DateTime(timezone=True), onupdate=func.now())

    tags = Column(ARRAY(Text), nullable=False,
        default=cast(array([], type_=Text), ARRAY(Text)))

    followers = relationship('User', secondary=follows,
        primaryjoin=id == follows.c.to_id,
        secondaryjoin=id == follows.c.from_id,
        order_by=follows.c.id,
        backref='friends', lazy='subquery')

    tweets = relationship('Tweet',
        primaryjoin='User.id == foreign(Tweet.user_id)',
        backref='user', lazy='subquery', viewonly=True)

    __table_args__ = (
        Index('ix_user_name_lower', func.lower('name')),
        Index('ix_user_tags', tags, postgresql_using='gin'),
    )

Project Side-Quest

Honeypot

Doxxing

Data Collection

  • Browser fingerprinting
  • WebRTC de-anonymization
  • IP leakage

Next Steps

  • Crowd-funding campaign
  • Continue data collection and analysis

Questions?

Twitter Dev Conf Eng

By Yuval Adam

Twitter Dev Conf Eng

  • 1,496