Thursday, August 27, 2020

SocialNets! let's connect networks

Have you ever found yourself in a situation where you can't connect to your company VPN and want to do some quick tests on hosts lying inside the VPN? Or want to connect to machines in VPN via your mobile phone while travelling?

Let's think what is hurdle here?

  • We can't reach these hosts from outside even if they are listening

 

Solution

  • These hosts can connect to internet
  • Create a mediator to which these hosts connect and listen for commands.

 

Sub-problems in this solution

  • Create a mediator in the internet? 
    • Should we buy a public IP?
  • What about authentication of the users?

 

Solution

  • We don't need to buy a IP when messaging services exist in the internet. Let's consider such a system, "Facebook"
    • Facebook allows developers to create test user accounts which are disposable.
    • Facebook also messaging service which allows exchange of messages between these users and no real facebook user can send messages to these users.
    • What about Authentication?
      • Let facebook do it for you. 
  • We can run some custom Facebook client on the hosts inside the VPN and let them execute the tasks sent to it as a text message.

 

Enough, show me a demo

  • For this example's purpose we need two Facebook test users, let's call them F1 and F2. You have to login to facebook using these user credentials and make them friends.
  • To create a custom Facebook client, we will use the fbchat python library. To install it using pip run the below command   
pip install fbchat
  • Here is the python code which will execute the messages sent to it as a command, create a file called novpn.py and add the below content. Replace the user, passwd, recvFrom values in this file.
  • Run the code in a host which is accessible in VPN

 python novpn.py

  • Login to facebook using the credentials of user F2 and send messages to F1. They will be run as bash commands and output will be sent right back to you.

 

Demo


 

Limitations

  1. Large messages are not supported (I haven't tested the max limit, comment it if you get to know about it) 
  2. There will be a delay between message transfers
  3. Interactive applications are not supported (vim, nano, more, less etc)

 

Improvements

  1. We can write a custom client, to address the above mentioned limitations using the same fbchat APIs.

 

-madhusoodan

Tuesday, July 14, 2020

VPN fishing

Recently I encountered an interesting scenario where a link I clicked on a link in an email local to our VPN opened a public website. Link was similar to

        swarm/changes/674362

Now, I was expecting some diff of files described in the mail but I found completely different stuff and I checked whether I am connected to the VPN or not. As you might expect, I was not. Some time later I thought we can use this to trick people to get their credentials for swarm. If you got the credentials, and if they are same as the NT credentials, (... think of the bad things you can do on your own)

A simpler explanation with Alice and Bob

1. Alice (A bad girl) has set up a public website with DNS name "xyz" which mimicks a site in VPN which both Alice and Bob can access (It's not mandatory that, Alice should have access to it)

2. Alice sends an email to Bob which contains a protected url as below

            xyz/foo/bar

3. Here it is assumed that, xyz is a site available in VPN as well as on the internet.

4. If Bob is connected to VPN and opens the URL, he will hit the local (present in the VPN) site and things will go well

5. If Bob is not connected to VPN he will connect to the public website (URL in the address bar will still be same) and he will enters his credentials to access /foo/bar and will be compromised.

How can one protect themselves?

   - Orgs can WARN their employees when they visit public sites (or block these sites) whose DNS names match the local site DNS names.

Thursday, July 2, 2020

Building HBase 1.3.1 with JDK 8

HBase is a opensource NoSQL store built on top of Hadoop HDFS filesystem. Read more about it here

Building HBase 1.3.1 with JDK 8 will bring out some new problems (Well there are some other issues as well). This blog post is to help people who are walking on the same way as I am.


Assumptions

1. You have installed JDK 8
2. HBase uses maven for builds, you should have installed maven.
3. The sources are already downloaded and are present in /home/xyz/hbase

mvn install won't work?

No, you will hit some compilation issues and some shell script failures.

Compilation error
[ERROR] Failed to execute goal org.codehaus.mojo:findbugs-maven-plugin:3.0.0:findbugs (default) on project hbase: Unable to parse configuration of mojo org.codehaus.mojo:findbugs-maven-plugin:3.0.0:findbugs for parameter pluginArtifacts: Cannot assign configuration entry 'pluginArtifacts' with value '${plugin.artifacts}' of type java.util.Collections.UnmodifiableRandomAccessList to property of type java.util.ArrayList -> [Help 1]

Shell script failure
[ERROR] Failed to execute goal org.codehaus.mojo:exec-maven-plugin:1.4.0:exec (concat-NOTICE-files) on project hbase-assembly: Command execution failed.: Process exited with an error: 1 (Exit value: 1) -> [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.codehaus.mojo:exec-maven-plugin:1.4.0:exec (concat-NOTICE-files) on project hbase-assembly: Command execution failed.

Ok how do I solve them?

1. Edit the file /home/xyz/hbase/pom.xml and make the following changes.

     Before
        ...
        <plugin>
          <groupId>org.codehaus.mojo</groupId>
          <artifactId>findbugs-maven-plugin</artifactId>
          <version>3.0.0</version>
          <!--NOTE: Findbugs 3.0.0 requires jdk7-->
        ...

     After
        ...
        <plugin>
          <groupId>org.codehaus.mojo</groupId>
          <artifactId>findbugs-maven-plugin</artifactId>
          <version>3.0.4</version>
          <!--NOTE: Findbugs 3.0.0 requires jdk7-->
        ...


2. Edit the file /home/xyz/hbase/hbase-assembly/pom.xml and make the following changes. New versions of bash seems to not accept the extra line at the end

     Before
        ...
            <argument>bash</argument>
            <argument>-c</argument>
            <argument>cat maven-shared-archive-resources/META-INF/NOTICE \
                `find ${project.build.directory}/dependency -iname NOTICE -or -iname NOTICE.txt` \
            </argument>
        ....
     After
        ...
            <argument>bash</argument>
            <argument>-c</argument>
            <argument>cat maven-shared-archive-resources/META-INF/NOTICE \
                `find ${project.build.directory}/dependency -iname NOTICE -or -iname NOTICE.txt`
            </argument>
        ...


-madhusoodan

Wednesday, July 1, 2020

Building JDK 8 on Fedora 31 (GCC 9.2.1)

This blog lists out the steps to build JDK 8 on Fedora 31. I had some compilation problems while building it, so you may find this useful.

1. I was building the openjdk 8u, so we have to clone it from the public repo

    $ hg clone http://hg.openjdk.java.net/jdk8u/jdk8u

2. This will just bring some source and scripts which are necessary to get the actual JDK and hotspot sources.

3. To get the actual sources, run the utility shell script

    $ ./get_source.sh

4. Configure the build for your system

    $ bash configure

5. Add below options if you want debug symbols

    $ bash configure --with-debug-level=slowdebug

6. Set the environment variable to resolve the compilation errors

    $ export CFLAGS="-Wno-return-type"

7. Run the build

    $ make

Little more info

gcc version

$ gcc --version
gcc (GCC) 9.2.1 20190827 (Red Hat 9.2.1-1)
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Thursday, June 18, 2020

JVM agents and JIT

So... one day I notice a JVM hanging at the startup in one of our servers. It has not logged anything after it has started. `jstack` showed that the process is executing some `premain` function

Jstack

# jstack 24692
...
"main" #1 prio=5 os_prio=0 tid=0x00007f228000a000 nid=0x6075 runnable [0x00007f2287823000]
   java.lang.Thread.State: RUNNABLE
        at sun.security.provider.SHA2.implCompress(SHA2.java:201)
        at sun.security.provider.DigestBase.implCompressMultiBlock(DigestBase.java:141)
        at sun.security.provider.DigestBase.engineUpdate(DigestBase.java:128)
        at java.security.MessageDigest$Delegate.engineUpdate(MessageDigest.java:584)
        at java.security.MessageDigest.update(MessageDigest.java:335)
        at com.sun.crypto.provider.HmacCore.engineUpdate(HmacCore.java:161)
        at javax.crypto.Mac.update(Mac.java:485)
        at com.sun.crypto.provider.PBKDF2KeyImpl.deriveKey(PBKDF2KeyImpl.java:178)
        at com.sun.crypto.provider.PBKDF2KeyImpl.<init>(PBKDF2KeyImpl.java:113)
        at com.sun.crypto.provider.PBKDF2Core.engineGenerateSecret(PBKDF2Core.java:69)
        at javax.crypto.SecretKeyFactory.generateSecret(SecretKeyFactory.java:336)
        at com.mmp.jvmtiperf.MyAgent.decrypt(MyAgent.java:17)
        at com.mmp.jvmtiperf.MyAgent.premain(MyAgent.java:28)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:386)
        at sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:401)


I also profiled the JVM, and this was the most common stack

--- 10001689 ns (0.04%), 1 sample
  [ 0] sun.misc.Unsafe.getInt
  [ 1] sun.security.provider.ByteArrayAccess.b2iBig64
  [ 2] sun.security.provider.SHA2.implCompress
  [ 3] sun.security.provider.SHA2.implDigest
  [ 4] sun.security.provider.DigestBase.engineDigest
  [ 5] sun.security.provider.DigestBase.engineDigest
  [ 6] java.security.MessageDigest$Delegate.engineDigest
  [ 7] java.security.MessageDigest.digest
  [ 8] com.sun.crypto.provider.HmacCore.engineDoFinal
  [ 9] javax.crypto.Mac.doFinal
  [10] javax.crypto.Mac.doFinal
  [11] com.sun.crypto.provider.PBKDF2KeyImpl.deriveKey
  [12] com.sun.crypto.provider.PBKDF2KeyImpl.<init>
  [13] com.sun.crypto.provider.PBKDF2Core.engineGenerateSecret
  [14] javax.crypto.SecretKeyFactory.generateSecret
  [15] com.mmp.jvmtiperf.MyAgent.decrypt
  [16] com.mmp.jvmtiperf.MyAgent.premain
  [17] sun.reflect.NativeMethodAccessorImpl.invoke0
  [18] sun.reflect.NativeMethodAccessorImpl.invoke
  [19] sun.reflect.DelegatingMethodAccessorImpl.invoke
  [20] java.lang.reflect.Method.invoke
  [21] sun.instrument.InstrumentationImpl.loadClassAndStartAgent
  [22] sun.instrument.InstrumentationImpl.loadClassAndCallPremain

          ns  percent  samples  top
  ----------  -------  -------  ---
 13747492952   52.44%     1374  sun.security.provider.SHA2.lf_S
  1920993571    7.33%      192  sun.security.provider.SHA2.implCompress
  1801015904    6.87%      180  sun.security.provider.SHA2.lf_R
  1190642160    4.54%      119  sun.security.provider.SHA2.lf_maj
  1160569433    4.43%      116  sun.security.provider.SHA2.lf_ch
  1040701461    3.97%      104  Interpreter
  1010585056    3.86%      101  sun.security.provider.SHA2.lf_sigma0
   560312244    2.14%       56  sun.security.provider.SHA2.lf_sigma1
   560302440    2.14%       56  sun.security.provider.SHA2.lf_delta1
   560296929    2.14%       56  sun.security.provider.SHA2.lf_delta0
   300184334    1.15%       30  java.lang.Integer.reverseBytes
   170088977    0.65%       17  java.util.Arrays.fill
   160085552    0.61%       16  sun.security.provider.DigestBase.engineUpdate
   150083336    0.57%       15  sun.security.provider.ByteArrayAccess.b2iBig64


Agents are common in Java world and premain is a function implemented by a java agent. So I checked the agent attached to this JVM. It was a silly little code, which used to compute some secret and set it as a JVM argument. Since I can't share the complete code here, I extracted a MVCE out of it which is given below

$ cat MyAgent.java
package com.mmp.jvmtiperf;

import javax.crypto.spec.*;
import java.lang.instrument.Instrumentation;
import java.security.spec.*;
import java.util.Base64;
import javax.crypto.*;

public class MyAgent {

    public static String decrypt(String strToDecrypt, String secret) {
        try {
            byte[] iv = new byte[16];
            IvParameterSpec ivspec = new IvParameterSpec(iv);
            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
            KeySpec spec = new PBEKeySpec(secret.toCharArray(), "hello@123".getBytes(), 65536, 256);
            SecretKey tmp = factory.generateSecret(spec);
            SecretKeySpec secretKey = new SecretKeySpec(tmp.getEncoded(), "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
            cipher.init(2, secretKey, ivspec);
            return new String(cipher.doFinal(Base64.getDecoder().decode(strToDecrypt)));
        } catch (Exception e) {
            return null;
        }
    }

    public static void premain(String agentArgs, Instrumentation inst) {
        System.setProperty("mySecretProp",
           decrypt("89/LaUAGfN8VMrUew8wuylMyzgcCxC6Af4DVLROEouw=", "supersecret"));
    }
}


To compile and package this, run the below commands

$ javac MyAgent.java
$ mkdir -p com/mmp/jvmtiperf
$ cp MyAgent.class com/mmp/jvmtiperf
$ mkdir META-INF
$ echo "Manifest-Version: 1.0
Implementation-Title:   myagent
Premain-Class: com.mmp.jvmtiperf.MyAgent
Implementation-Version: 1.0.0" > META-INF/MANIFEST.MF
$ jar cvf myagent.jar com/mmp/jvmtiperf
$ zip myagent.jar META-INF/MANIFEST.MF

Now to run this, we need a test program

$ cat test.java
class test {
        public static void main(String a[]) {
                if(a.length > 0 && a[0].equals("-runPremain"))
                        com.mmp.jvmtiperf.MyAgent.premain(a[0], null);
                System.out.println("exitting");
        }
}

Just running this code (using the below command) runs real quick

$ javac test.java
$ time java  -cp . test -runPremain
exitting

real    0m0.629s
user    0m1.282s
sys     0m0.083s


This is confusing, because the app used to spend most of its time here in the agent. Only difference here is the code is executed from the `main`, while in our hung application, it was called from `premain`, so we need to test it in the same way.

$ time java -javaagent:myagent.jar -cp . test
exitting

real    0m32.057s
user    0m32.020s
sys     0m0.054s


Ok, we were able to reproduce the issue, but why the function called from `premain` was slower than the function called from the `main`? Let's profile this fast JVM to understand this

$ java -cp . -agentpath:/root/perf/async-profiler-master/build/libasyncProfiler.so=start,file=foo test -runPremain
$ cat perf
....
          ns  percent  samples  top
  ----------  -------  -------  ---
   140071867   23.33%       14  sun.security.provider.SHA2.implCompress
   110105345   18.34%       11  Method::make_jmethod_id(ClassLoaderData*, Method*)
    20016638    3.33%        2  Rewriter::scan_method(Method*, bool, bool*)
    20009898    3.33%        2  __malloc
    19997059    3.33%        2  sun.security.provider.SHA.implCompress
    10022555    1.67%        1  _raw_spin_unlock_irqrestore_[k]
    10016146    1.67%        1  __do_page_fault_[k]
    10011639    1.67%        1  __GI___pthread_mutex_lock
    10011504    1.67%        1  java_lang_String::equals(oopDesc*, unsigned short*, int)
    10011372    1.67%        1  Interpreter
    10009534    1.67%        1  java.io.ByteArrayInputStream.available
    10009404    1.67%        1  __pthread_getspecific
...


If we compare the profile results, the JVM's Interpreter is executed more times in slow JVM than the faster one

Slower one

  1160569433    4.43%      116  sun.security.provider.SHA2.lf_ch
  1040701461    3.97%      104  Interpreter
  1010585056    3.86%      101  sun.security.provider.SHA2.lf_sigma0

Faster one
    10011504    1.67%        1  java_lang_String::equals(oopDesc*, unsigned short*, int)
    10011372    1.67%        1  Interpreter
    10009534    1.67%        1  java.io.ByteArrayInputStream.available


So, something related to the bytecode interpreter is wrong (104 is the number of times it appered on the stack). So, let's see what is going on inside the JVM. Let's use


Compilation in fast JVM (Refer the images at the end to see all the compiled packages.)

$ java -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompilation  -cp . test -runPremain | grep 'sun.security.provider.SHA2.'
    ...
    192  206       3       sun.security.provider.SHA2::lf_S (11 bytes)
    193  207       3       sun.security.provider.SHA2::lf_R (4 bytes)
    193  209       3       sun.security.provider.SHA2::lf_sigma1 (21 bytes)
    193  210       3       sun.security.provider.SHA2::lf_ch (10 bytes)
    193  211       3       sun.security.provider.SHA2::lf_sigma0 (20 bytes)
    ...


Compilation in fast JVM (Nothing from sun.security was compiled)

$ java -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompilation -javaagent:myagent.jar -cp . test   | grep 'sun.security.provider.SHA2::lf_S'
$


So, it was the JIT compiler who was not compiling the crypto packages and letting them run on the Interpreter. Solution? I still need to find it :P



Images

(Snapshot from JITWatch for fast JVM)


(Snapshot from JITWatch for slow JVM)